Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time axis ticks formatting for base and senior unit #4268

Merged
merged 16 commits into from Jun 15, 2017
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/axes/styling.md
Expand Up @@ -35,3 +35,27 @@ The tick configuration is nested under the scale configuration in the `ticks` ke
| `fontSize` | `Number` | `12` | Font size for the tick labels.
| `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
| `reverse` | `Boolean` | `false` | Reverses order of tick labels.
| `minor` | `object` | `{}` | Minor ticks configuration. Ommited options are inherited from options above.
| `major` | `object` | `{}` | Major ticks configuration. Ommited options are inherited from options above.

## Minor Tick Configuration
The minorTick configuration is nested under the ticks configuration in the `minor` key. It defines options for the minor tick marks that are generated by the axis. Omitted options are inherited from `ticks` configuration.

| Name | Type | Default | Description
| -----| ---- | --------| -----------
| `callback` | `Function` | | Returns the string representation of the tick value as it should be displayed on the chart. See [callback](../axes/labelling.md#creating-custom-tick-formats).
| `fontColor` | Color | `'#666'` | Font color for tick labels.
| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the tick labels, follows CSS font-family options.
| `fontSize` | `Number` | `12` | Font size for the tick labels.
| `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).

## Major Tick Configuration
The majorTick configuration is nested under the ticks configuration in the `major` key. It defines options for the major tick marks that are generated by the axis. Omitted options are inherited from `ticks` configuration.

| Name | Type | Default | Description
| -----| ---- | --------| -----------
| `callback` | `Function` | | Returns the string representation of the tick value as it should be displayed on the chart. See [callback](../axes/labelling.md#creating-custom-tick-formats).
| `fontColor` | Color | `'#666'` | Font color for tick labels.
| `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the tick labels, follows CSS font-family options.
| `fontSize` | `Number` | `12` | Font size for the tick labels.
| `fontStyle` | `String` | `'normal'` | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
1 change: 0 additions & 1 deletion samples/scales/time/line-point-data.html
Expand Up @@ -104,7 +104,6 @@
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myLine = new Chart(ctx, config);

};

document.getElementById('randomizeData').addEventListener('click', function() {
Expand Down
1 change: 1 addition & 0 deletions src/core/core.controller.js
Expand Up @@ -265,6 +265,7 @@ module.exports = function(Chart) {
});

scales[scale.id] = scale;
scale.mergeTicksOptions();

// TODO(SB): I think we should be able to remove this custom case (options.scale)
// and consider it as a regular scale part of the "scales"" map only! This would
Expand Down
43 changes: 36 additions & 7 deletions src/core/core.scale.js
Expand Up @@ -48,7 +48,9 @@ module.exports = function(Chart) {
autoSkipPadding: 0,
labelOffset: 0,
// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
callback: Chart.Ticks.formatters.values
callback: Chart.Ticks.formatters.values,
minor: {},
major: {}
}
};

Expand Down Expand Up @@ -94,6 +96,29 @@ module.exports = function(Chart) {
// Any function defined here is inherited by all scale types.
// Any function can be extended by the scale type

mergeTicksOptions: function() {
var ticks = this.options.ticks;
if (ticks.minor === false) {
ticks.minor = {
display: false
};
}
if (ticks.major === false) {
ticks.major = {
display: false
};
}
for (var key in ticks) {
if (key !== 'major' && key !== 'minor') {
if (typeof ticks.minor[key] === 'undefined') {
ticks.minor[key] = ticks[key];
}
if (typeof ticks.major[key] === 'undefined') {
ticks.major[key] = ticks[key];
}
}
}
},
beforeUpdate: function() {
helpers.callback(this.options.beforeUpdate, [this]);
},
Expand Down Expand Up @@ -486,7 +511,8 @@ module.exports = function(Chart) {

var context = me.ctx;
var globalDefaults = Chart.defaults.global;
var optionTicks = options.ticks;
var optionTicks = options.ticks.minor;
var optionMajorTicks = options.ticks.major || optionTicks;
var gridLines = options.gridLines;
var scaleLabel = options.scaleLabel;

Expand All @@ -503,6 +529,8 @@ module.exports = function(Chart) {

var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
var tickFont = parseFontOptions(optionTicks);
var majorTickFontColor = helpers.getValueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
var majorTickFont = parseFontOptions(optionMajorTicks);

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

Expand All @@ -513,9 +541,6 @@ module.exports = function(Chart) {
var cosRotation = Math.cos(labelRotationRadians);
var longestRotatedLabel = me.longestLabelWidth * cosRotation;

// Make sure we draw text in the correct color and font
context.fillStyle = tickFontColor;

var itemsToDraw = [];

if (isHorizontal) {
Expand Down Expand Up @@ -547,7 +572,8 @@ module.exports = function(Chart) {
var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl;
var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom;

helpers.each(me.ticks, function(label, index) {
helpers.each(me.ticks, function(tick, index) {
var label = (tick && tick.value) || tick;
// If the callback returned a null or undefined value, do not draw this line
if (label === undefined || label === null) {
return;
Expand Down Expand Up @@ -645,6 +671,7 @@ module.exports = function(Chart) {
glBorderDashOffset: borderDashOffset,
rotation: -1 * labelRotationRadians,
label: label,
major: tick.major,
textBaseline: textBaseline,
textAlign: textAlign
});
Expand Down Expand Up @@ -678,10 +705,12 @@ module.exports = function(Chart) {
}

if (optionTicks.display) {
// Make sure we draw text in the correct color and font
context.save();
context.translate(itemToDraw.labelX, itemToDraw.labelY);
context.rotate(itemToDraw.rotation);
context.font = tickFont.font;
context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
context.textBaseline = itemToDraw.textBaseline;
context.textAlign = itemToDraw.textAlign;

Expand Down
39 changes: 31 additions & 8 deletions src/scales/scale.time.js
Expand Up @@ -25,9 +25,9 @@ module.exports = function(Chart) {
displayFormats: {
millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
second: 'h:mm:ss a', // 11:20:01 AM
minute: 'h:mm:ss a', // 11:20:01 AM
hour: 'MMM D, hA', // Sept 4, 5PM
day: 'll', // Sep 4 2015
minute: 'h:mm a', // 11:20 AM
hour: 'hA', // 5PM
day: 'MMM D', // Sep 4
week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should change this to MMM D as well

month: 'MMM YYYY', // Sept 2015
quarter: '[Q]Q - YYYY', // Q3
Expand All @@ -45,6 +45,8 @@ module.exports = function(Chart) {
throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
}

this.mergeTicksOptions();

Chart.Scale.prototype.initialize.call(this);
},
determineDataLimits: function() {
Expand Down Expand Up @@ -182,14 +184,34 @@ module.exports = function(Chart) {
},
// Function to format an individual tick mark
tickFormatFunction: function(tick, index, ticks) {
var formattedTick = tick.format(this.displayFormat);
var tickOpts = this.options.ticks;
var formattedTick;
var tickClone = tick.clone();
var tickTimestamp = tick.valueOf();
var major = false;
var tickOpts;
if (this.majorUnit && this.majorDisplayFormat && tickTimestamp === tickClone.startOf(this.majorUnit).valueOf()) {
// format as major unit
formattedTick = tick.format(this.majorDisplayFormat);
tickOpts = this.options.ticks.major;
major = true;
} else {
// format as minor (base) unit
formattedTick = tick.format(this.displayFormat);
tickOpts = this.options.ticks.minor;
}

var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);

if (callback) {
return callback(formattedTick, index, ticks);
return {
value: callback(formattedTick, index, ticks),
major: major
};
}
return formattedTick;
return {
value: formattedTick,
major: major
};
},
convertTicksToLabels: function() {
var me = this;
Expand Down Expand Up @@ -257,11 +279,12 @@ module.exports = function(Chart) {
var me = this;

me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []);
var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []).value;
var tickLabelWidth = me.getLabelWidth(exampleLabel);

var innerWidth = me.isHorizontal() ? me.width : me.height;
var labelCapacity = innerWidth / tickLabelWidth;

return labelCapacity;
}
});
Expand Down
4 changes: 4 additions & 0 deletions test/specs/core.helpers.tests.js
Expand Up @@ -215,6 +215,8 @@ describe('Core helper tests', function() {
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0,
minor: {},
major: {},
},
type: 'linear'
}, {
Expand Down Expand Up @@ -253,6 +255,8 @@ describe('Core helper tests', function() {
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0,
minor: {},
major: {},
},
type: 'linear'
}]
Expand Down
4 changes: 3 additions & 1 deletion test/specs/scale.category.tests.js
Expand Up @@ -44,7 +44,9 @@ describe('Category scale tests', function() {
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0
labelOffset: 0,
minor: {},
major: {},
}
});

Expand Down
4 changes: 3 additions & 1 deletion test/specs/scale.linear.tests.js
Expand Up @@ -42,7 +42,9 @@ describe('Linear Scale', function() {
callback: defaultConfig.ticks.callback, // make this work nicer, then check below
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0
labelOffset: 0,
minor: {},
major: {},
}
});

Expand Down
4 changes: 3 additions & 1 deletion test/specs/scale.logarithmic.tests.js
Expand Up @@ -41,7 +41,9 @@ describe('Logarithmic Scale tests', function() {
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0
labelOffset: 0,
minor: {},
major: {},
},
});

Expand Down
4 changes: 3 additions & 1 deletion test/specs/scale.radialLinear.tests.js
Expand Up @@ -58,7 +58,9 @@ describe('Test the radial linear scale', function() {
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0
labelOffset: 0,
minor: {},
major: {},
},
});

Expand Down