Skip to content

Commit 14007a9

Browse files
nagixsimonbrunel
authored andcommitted
Fix ticks.minor and ticks.major configuration issues (#6102)
1 parent a43e3b0 commit 14007a9

File tree

5 files changed

+184
-42
lines changed

5 files changed

+184
-42
lines changed

docs/axes/labelling.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ var chart = new Chart(ctx, {
4242
}
4343
});
4444
```
45+
46+
The third parameter passed to the callback function is an array of labels, but in the time scale, it is an array of `{label: string, major: boolean}` objects.

src/core/core.scale.js

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,24 @@ function computeTextSize(context, tick, font) {
9999
context.measureText(tick).width;
100100
}
101101

102+
function parseFontOptions(options, nestedOpts) {
103+
return helpers.extend(helpers.options._parseFont({
104+
fontFamily: valueOrDefault(nestedOpts.fontFamily, options.fontFamily),
105+
fontSize: valueOrDefault(nestedOpts.fontSize, options.fontSize),
106+
fontStyle: valueOrDefault(nestedOpts.fontStyle, options.fontStyle),
107+
lineHeight: valueOrDefault(nestedOpts.lineHeight, options.lineHeight)
108+
}), {
109+
color: helpers.options.resolve([nestedOpts.fontColor, options.fontColor, defaults.global.defaultFontColor])
110+
});
111+
}
112+
113+
function parseTickFontOptions(options) {
114+
var minor = parseFontOptions(options, options.minor);
115+
var major = options.major.enabled ? parseFontOptions(options, options.major) : minor;
116+
117+
return {minor: minor, major: major};
118+
}
119+
102120
module.exports = Element.extend({
103121
/**
104122
* Get the padding needed for the scale
@@ -128,29 +146,16 @@ module.exports = Element.extend({
128146
// Any function defined here is inherited by all scale types.
129147
// Any function can be extended by the scale type
130148

149+
/**
150+
* Provided for backward compatibility, not available anymore
151+
* @function Chart.Scale.mergeTicksOptions
152+
* @deprecated since version 2.8.0
153+
* @todo remove at version 3
154+
*/
131155
mergeTicksOptions: function() {
132-
var ticks = this.options.ticks;
133-
if (ticks.minor === false) {
134-
ticks.minor = {
135-
display: false
136-
};
137-
}
138-
if (ticks.major === false) {
139-
ticks.major = {
140-
display: false
141-
};
142-
}
143-
for (var key in ticks) {
144-
if (key !== 'major' && key !== 'minor') {
145-
if (typeof ticks.minor[key] === 'undefined') {
146-
ticks.minor[key] = ticks[key];
147-
}
148-
if (typeof ticks.major[key] === 'undefined') {
149-
ticks.major[key] = ticks[key];
150-
}
151-
}
152-
}
156+
// noop
153157
},
158+
154159
beforeUpdate: function() {
155160
helpers.callback(this.options.beforeUpdate, [this]);
156161
},
@@ -628,7 +633,7 @@ module.exports = Element.extend({
628633
_autoSkip: function(ticks) {
629634
var me = this;
630635
var isHorizontal = me.isHorizontal();
631-
var optionTicks = me.options.ticks.minor;
636+
var optionTicks = me.options.ticks;
632637
var tickCount = ticks.length;
633638
var skipRatio = false;
634639
var maxTicks = optionTicks.maxTicksLimit;
@@ -673,7 +678,7 @@ module.exports = Element.extend({
673678
_tickSize: function() {
674679
var me = this;
675680
var isHorizontal = me.isHorizontal();
676-
var optionTicks = me.options.ticks.minor;
681+
var optionTicks = me.options.ticks;
677682

678683
// Calculate space needed by label in axis direction.
679684
var rot = helpers.toRadians(me.labelRotation);
@@ -683,7 +688,7 @@ module.exports = Element.extend({
683688
var padding = optionTicks.autoSkipPadding || 0;
684689
var w = (me.longestLabelWidth + padding) || 0;
685690

686-
var tickFont = helpers.options._parseFont(optionTicks);
691+
var tickFont = parseTickFontOptions(optionTicks).minor;
687692
var h = (me._maxLabelLines * tickFont.lineHeight + padding) || 0;
688693

689694
// Calculate space needed for 1 tick in axis direction.
@@ -732,10 +737,7 @@ module.exports = Element.extend({
732737

733738
var chart = me.chart;
734739
var context = me.ctx;
735-
var globalDefaults = defaults.global;
736-
var defaultFontColor = globalDefaults.defaultFontColor;
737-
var optionTicks = options.ticks.minor;
738-
var optionMajorTicks = options.ticks.major || optionTicks;
740+
var optionTicks = options.ticks;
739741
var gridLines = options.gridLines;
740742
var scaleLabel = options.scaleLabel;
741743
var position = options.position;
@@ -744,20 +746,15 @@ module.exports = Element.extend({
744746
var isMirrored = optionTicks.mirror;
745747
var isHorizontal = me.isHorizontal();
746748

747-
var parseFont = helpers.options._parseFont;
748749
var ticks = optionTicks.display && optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
749-
var tickFontColor = valueOrDefault(optionTicks.fontColor, defaultFontColor);
750-
var tickFont = parseFont(optionTicks);
751-
var lineHeight = tickFont.lineHeight;
752-
var majorTickFontColor = valueOrDefault(optionMajorTicks.fontColor, defaultFontColor);
753-
var majorTickFont = parseFont(optionMajorTicks);
750+
var tickFonts = parseTickFontOptions(optionTicks);
754751
var tickPadding = optionTicks.padding;
755752
var labelOffset = optionTicks.labelOffset;
756753

757754
var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
758755

759-
var scaleLabelFontColor = valueOrDefault(scaleLabel.fontColor, defaultFontColor);
760-
var scaleLabelFont = parseFont(scaleLabel);
756+
var scaleLabelFontColor = valueOrDefault(scaleLabel.fontColor, defaults.global.defaultFontColor);
757+
var scaleLabelFont = helpers.options._parseFont(scaleLabel);
761758
var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
762759
var labelRotationRadians = helpers.toRadians(me.labelRotation);
763760

@@ -794,6 +791,8 @@ module.exports = Element.extend({
794791
}
795792

796793
var label = tick.label;
794+
var tickFont = tick.major ? tickFonts.major : tickFonts.minor;
795+
var lineHeight = tickFont.lineHeight;
797796
var lineWidth, lineColor, borderDash, borderDashOffset;
798797
if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
799798
// Draw the first index specially
@@ -918,12 +917,14 @@ module.exports = Element.extend({
918917
}
919918

920919
if (optionTicks.display) {
920+
var tickFont = itemToDraw.major ? tickFonts.major : tickFonts.minor;
921+
921922
// Make sure we draw text in the correct color and font
922923
context.save();
923924
context.translate(itemToDraw.labelX, itemToDraw.labelY);
924925
context.rotate(itemToDraw.rotation);
925-
context.font = itemToDraw.major ? majorTickFont.string : tickFont.string;
926-
context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
926+
context.font = tickFont.string;
927+
context.fillStyle = tickFont.color;
927928
context.textBaseline = 'middle';
928929
context.textAlign = itemToDraw.textAlign;
929930

@@ -933,7 +934,7 @@ module.exports = Element.extend({
933934
for (var i = 0; i < label.length; ++i) {
934935
// We just make sure the multiline element is a string here..
935936
context.fillText('' + label[i], 0, y);
936-
y += lineHeight;
937+
y += tickFont.lineHeight;
937938
}
938939
} else {
939940
context.fillText(label, 0, y);

src/scales/scale.time.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -678,11 +678,17 @@ module.exports = Scale.extend({
678678
var majorUnit = me._majorUnit;
679679
var majorFormat = formats[majorUnit];
680680
var majorTime = +adapter.startOf(time, majorUnit);
681-
var majorTickOpts = options.ticks.major;
681+
var tickOpts = options.ticks;
682+
var majorTickOpts = tickOpts.major;
682683
var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
683684
var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);
684-
var tickOpts = major ? majorTickOpts : options.ticks.minor;
685-
var formatter = valueOrDefault(tickOpts.callback, tickOpts.userCallback);
685+
var nestedTickOpts = major ? majorTickOpts : tickOpts.minor;
686+
var formatter = helpers.options.resolve([
687+
nestedTickOpts.callback,
688+
nestedTickOpts.userCallback,
689+
tickOpts.callback,
690+
tickOpts.userCallback
691+
]);
686692

687693
return formatter ? formatter(label, index, ticks) : label;
688694
},

test/specs/global.deprecations.tests.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
describe('Deprecations', function() {
2+
describe('Version 2.9.0', function() {
3+
describe('Chart.Scale.mergeTicksOptions', function() {
4+
it('should be defined as a function', function() {
5+
expect(typeof Chart.Scale.prototype.mergeTicksOptions).toBe('function');
6+
});
7+
});
8+
});
9+
210
describe('Version 2.8.0', function() {
311
[
412
['Bar', 'bar'],

test/specs/scale.time.tests.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,131 @@ describe('Time scale tests', function() {
616616
expect(xScale.getLabelForIndex(6, 0)).toBe('2015-01-10T12:00');
617617
});
618618

619+
describe('when ticks.callback is specified', function() {
620+
beforeEach(function() {
621+
this.chart = window.acquireChart({
622+
type: 'line',
623+
data: {
624+
datasets: [{
625+
xAxisID: 'xScale0',
626+
data: [0, 0]
627+
}],
628+
labels: ['2015-01-01T20:00:00', '2015-01-01T20:01:00']
629+
},
630+
options: {
631+
scales: {
632+
xAxes: [{
633+
id: 'xScale0',
634+
type: 'time',
635+
ticks: {
636+
callback: function(value) {
637+
return '<' + value + '>';
638+
}
639+
}
640+
}]
641+
}
642+
}
643+
});
644+
this.scale = this.chart.scales.xScale0;
645+
});
646+
647+
it('should get the correct labels for ticks', function() {
648+
var scale = this.scale;
649+
650+
expect(scale._ticks.map(function(tick) {
651+
return tick.major;
652+
})).toEqual([true, false, false, false, false, false, true]);
653+
expect(scale.ticks).toEqual(['<8:00:00 pm>', '<8:00:10 pm>', '<8:00:20 pm>', '<8:00:30 pm>', '<8:00:40 pm>', '<8:00:50 pm>', '<8:01:00 pm>']);
654+
});
655+
656+
it('should update ticks.callback correctly', function() {
657+
var chart = this.chart;
658+
var scale = this.scale;
659+
660+
chart.options.scales.xAxes[0].ticks.callback = function(value) {
661+
return '{' + value + '}';
662+
};
663+
chart.update();
664+
expect(scale.ticks).toEqual(['{8:00:00 pm}', '{8:00:10 pm}', '{8:00:20 pm}', '{8:00:30 pm}', '{8:00:40 pm}', '{8:00:50 pm}', '{8:01:00 pm}']);
665+
});
666+
});
667+
668+
describe('when ticks.major.callback and ticks.minor.callback are specified', function() {
669+
beforeEach(function() {
670+
this.chart = window.acquireChart({
671+
type: 'line',
672+
data: {
673+
datasets: [{
674+
xAxisID: 'xScale0',
675+
data: [0, 0]
676+
}],
677+
labels: ['2015-01-01T20:00:00', '2015-01-01T20:01:00']
678+
},
679+
options: {
680+
scales: {
681+
xAxes: [{
682+
id: 'xScale0',
683+
type: 'time',
684+
ticks: {
685+
callback: function(value) {
686+
return '<' + value + '>';
687+
},
688+
major: {
689+
enabled: true,
690+
callback: function(value) {
691+
return '[' + value + ']';
692+
}
693+
},
694+
minor: {
695+
callback: function(value) {
696+
return '(' + value + ')';
697+
}
698+
}
699+
}
700+
}]
701+
}
702+
}
703+
});
704+
this.scale = this.chart.scales.xScale0;
705+
});
706+
707+
it('should get the correct labels for major and minor ticks', function() {
708+
var scale = this.scale;
709+
710+
expect(scale._ticks.map(function(tick) {
711+
return tick.major;
712+
})).toEqual([true, false, false, false, false, false, true]);
713+
expect(scale.ticks).toEqual(['[8:00 pm]', '(8:00:10 pm)', '(8:00:20 pm)', '(8:00:30 pm)', '(8:00:40 pm)', '(8:00:50 pm)', '[8:01 pm]']);
714+
});
715+
716+
it('should only use ticks.minor callback if ticks.major.enabled is false', function() {
717+
var chart = this.chart;
718+
var scale = this.scale;
719+
720+
chart.options.scales.xAxes[0].ticks.major.enabled = false;
721+
chart.update();
722+
expect(scale.ticks).toEqual(['(8:00:00 pm)', '(8:00:10 pm)', '(8:00:20 pm)', '(8:00:30 pm)', '(8:00:40 pm)', '(8:00:50 pm)', '(8:01:00 pm)']);
723+
});
724+
725+
it('should use ticks.callback if ticks.major.callback is omitted', function() {
726+
var chart = this.chart;
727+
var scale = this.scale;
728+
729+
chart.options.scales.xAxes[0].ticks.major.callback = undefined;
730+
chart.update();
731+
expect(scale.ticks).toEqual(['<8:00 pm>', '(8:00:10 pm)', '(8:00:20 pm)', '(8:00:30 pm)', '(8:00:40 pm)', '(8:00:50 pm)', '<8:01 pm>']);
732+
});
733+
734+
it('should use ticks.callback if ticks.minor.callback is omitted', function() {
735+
var chart = this.chart;
736+
var scale = this.scale;
737+
738+
chart.options.scales.xAxes[0].ticks.minor.callback = undefined;
739+
chart.update();
740+
expect(scale.ticks).toEqual(['[8:00 pm]', '<8:00:10 pm>', '<8:00:20 pm>', '<8:00:30 pm>', '<8:00:40 pm>', '<8:00:50 pm>', '[8:01 pm]']);
741+
});
742+
});
743+
619744
it('should get the correct label when time is specified as a string', function() {
620745
var chart = window.acquireChart({
621746
type: 'line',

0 commit comments

Comments
 (0)