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

Conversation

hurskiy-andriy
Copy link
Contributor

Changed default formatting for time units.
Bold style added to senior unit tick labels.

@@ -681,7 +681,17 @@ module.exports = function(Chart) {
context.save();
context.translate(itemToDraw.labelX, itemToDraw.labelY);
context.rotate(itemToDraw.rotation);
context.font = tickFont.font;
var font = tickFont.font;
if (me.ticksAsTimestamps) {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure that adding in this detail the core scale is the best way to go

@@ -26,8 +26,8 @@ module.exports = function(Chart) {
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
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 get rid of :ss on this line

hour: 'MMM D, hA', // Sept 4, 5PM
day: 'll', // Sep 4 2015
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

@benmccann
Copy link
Contributor

@hurskiy-andriy could you rebase this PR against master?

@benmccann
Copy link
Contributor

I think that the main thing to address is etimberg's comment about modifying core.scale.js

The other thing I was going to mention was samples/scales/time/line.html. There are sort of weird dates that are bolded. I'm guessing this is because the majorUnit is week. Week and quarter don't make a lot of sense to me as being units people commonly refer to, so I would suggest we only use month and year as majorUnit

Copy link
Member

@simonbrunel simonbrunel left a comment

Choose a reason for hiding this comment

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

It seems this PR forces a specific design for the "major" tick (bold), right? is it a breaking change? I'm not sure everyone will want it that way, at least the font should be fully customizable?

@@ -1,5 +1,8 @@
'use strict';

var moment = require('moment');
moment = typeof(moment) === 'function' ? moment : window.moment;
Copy link
Member

Choose a reason for hiding this comment

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

Agree with @etimberg's comment, Moment should not leak in core.scale.js but stays confined in scale.time.js

@benmccann
Copy link
Contributor

I agree that having an option to control the formatting makes sense. That's what was discussed in issue #4187 describing the feature as well.

This is probably a good default to have. Here are some screenshots of the before and after. I think it's much cleaner and easier to digest the x-axis with this change.

Here's a sample from before:
before

Here's a sample with the changes:
after

@benmccann
Copy link
Contributor

@etimberg @simonbrunel I've been reviewing @hurskiy-andriy's change and trying to figure out how to remove moment from core.scale.js. I think the cleanest way to do this is to introduce the concept of major and minor ticks so that core.scale.js can draw them each differently

Right now all the ticks are stored in the ticks variable. Should we have a minorTicks and majorTicks and remove ticks? Or should we make ticks store an object like {value:123, major:true}? Other thoughts or suggestions?

@etimberg
Copy link
Member

I don't think we can just remove the ticks property since other stuff might use it. I'm ok with adding the concept of major ticks to the axis and storing them separately.

@hurskiy-andriy
Copy link
Contributor Author

Changed ticks store to array of objects like `{value: '12AM', major: true}

Copy link
Member

@etimberg etimberg left a comment

Choose a reason for hiding this comment

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

@simonbrunel do you think the changes to the values in the scale.ticks property would be considered a breaking change?

Chart.Scale.prototype.initialize.call(this);
},
mergeTicksOptions: function() {
Copy link
Member

Choose a reason for hiding this comment

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

The docs for this function imply that it should be applicable to all scales. Should mergeTicksOptions be moved to the base scale class?

Copy link
Member

Choose a reason for hiding this comment

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

Also, we should really mark all internal members private and make them public only if requested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry I can't find docs for mergeTicksOptions. Goal of this function is to fill majorTicks options with default options. Should I rename this function to fillTimeTicksOptions?

Copy link
Member

Choose a reason for hiding this comment

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

This method should apply to all scale, so the new major options can be used by other scale implementations. That's why this merging logic should be in the base core.scale.js.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok understood. Thanks!

@@ -36,6 +36,19 @@ module.exports = function(Chart) {
},
ticks: {
autoSkip: false
},
majorTicks: {
Copy link
Member

Choose a reason for hiding this comment

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

I liked to have all tick options scoped under the ticks key, but having it duplicated under majorTicks doesn't look ideal but also not obvious that it overrides the ticks options. Not sure either about this alternative, but what do you think about:

ticks: {
    // common tick options
    // ...
    minor: {
        // overrides for minor ticks only
    },
    major: {
        // overrides for major ticks only
    }
}

ticks.minor: false: don't show minor ticks
ticks.major: false: don't show major ticks

Copy link
Member

Choose a reason for hiding this comment

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

Also, defaults major tick options should be major: {}, no need to duplicate values if exactly the same, the merge process will take care of that (same for minor).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If minor ticks will fetch their options from options.ticks.minor I think it will be breaking change or at least we'll must to refactor all other scales to use options.ticks.minor options.
I suggest to use your variant but without minor key. In that case minor ticks will use common ticks options and major ticks will use major options. So ticks options will looks like:
ticks: { // common tick options // ... major: { // overrides for major ticks only } }

Copy link
Member

Choose a reason for hiding this comment

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

I mean, global options for ticks.minor and ticks.major would be empty objects:

ticks: {
  minor: {}, //< use common tick options
  major: {}  //< use common tick options
}

and we keep current global ticks options so when computing effective minor and major options, it would fallback to ticks global options:

  • (effective) minor options = deep merge(ticks, tick.minor)
  • (effective) major options = deep merge(ticks, tick.major)

It's not a breaking change because minor and major ticks would use the ticks values by default, same as what we have in 2.6. Also having the shorthand ticks.minor: false (same for major) to hide minor or major ticks would be great.

Copy link
Member

Choose a reason for hiding this comment

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

@etimberg @benmccann thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, @simonbrunel, I like your suggestion

Copy link
Member

Choose a reason for hiding this comment

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

@simonbrunel I like that suggestion as well 😄

@simonbrunel
Copy link
Member

@etimberg if scale.ticks are used by plugins, then it's a breaking change!

@benmccann
Copy link
Contributor

benmccann commented Jun 2, 2017

I just did an audit of all the charts and plugins under the chartjs group on GitHub. None are using scale.ticks besides chartjs-chart-financial. Don't worry about chartjs-chart-financial though because it hasn't published an initial release yet, and I'll take responsibility for updating it before then.

Interestingly I discovered that the linear gauge chart also has the concept of major and minor ticks and has majorTicks and minorTicks options. I like the syntax we came up with better than the syntax it uses, so I think we should still use ticks.major and ticks.minor and update the linear gauge chart accordingly. I filed an issue in that repo to track

@simonbrunel
Copy link
Member

@benmccann thanks, so it seems fine to change the internal structure of scale.ticks, could be interesting to add a note in the code that make it private explicitly. I would not really care about options consistency with the LinearGauge chart because it's still based on Chart.js 1.x.

@etimberg
Copy link
Member

etimberg commented Jun 7, 2017

@simonbrunel do you think this can be merged?

@simonbrunel
Copy link
Member

It depends if we want to change how the options are exposed ({ticks: {minor: {}, major: {}, ... common ... })

@benmccann
Copy link
Contributor

Yes, let's update that first. @hurskiy-andriy would you be able to update that before we merge this PR?

@hurskiy-andriy
Copy link
Contributor Author

Changed ticks storage back to array of string. Major ticks are determined through majorTicksIndexes array.

@benmccann
Copy link
Contributor

Thanks for changing the config options.

I'm curious why did you change the ticks storage back to an array of strings? I liked it better when you just had ticks instead of ticks and majorTicksIndexes. Is it possible to change it back?

@hurskiy-andriy
Copy link
Contributor Author

@benmccann

If scale.ticks are used by plugins, then it's a breaking change!
So I change ticks back to array of strings for compatibility.

@hurskiy-andriy
Copy link
Contributor Author

@benmccann @simonbrunel
I decided to revert back to array of string because the simonbrunel noticed in #4268 (comment)
Let's come to agreement what format should we use

@benmccann
Copy link
Contributor

@hurskiy-andriy he said afterwards in #4268 (comment):

thanks, so it seems fine to change the internal structure of scale.ticks

@hurskiy-andriy
Copy link
Contributor Author

Changed ticks storage to array of objects like {value: '12 PM', major: true}

Copy link
Member

@simonbrunel simonbrunel left a comment

Choose a reason for hiding this comment

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

Looks good, just a few minification notes

@@ -94,6 +96,28 @@ 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() {
if (this.options.ticks.minor === false) {
Copy link
Member

Choose a reason for hiding this comment

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

Minification: (this.options.ticks is used 11 times)

var ticks = this.options.ticks;
if (ticks.minor === false) {
// ...

@@ -486,7 +510,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 ? options.ticks.major : optionTicks;
Copy link
Member

Choose a reason for hiding this comment

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

var optionMajorTicks = options.ticks.major || optionTicks;

@@ -547,7 +571,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 = typeof tick === 'object' && typeof tick.value !== 'undefined' ? tick.value : tick;
Copy link
Member

Choose a reason for hiding this comment

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

var label = (tick && tick.value) || tick;

@@ -645,6 +670,7 @@ module.exports = function(Chart) {
glBorderDashOffset: borderDashOffset,
rotation: -1 * labelRotationRadians,
label: label,
major: tick.major === true,
Copy link
Member

Choose a reason for hiding this comment

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

Why not simply: major: tick.major?

Copy link
Member

@simonbrunel simonbrunel left a comment

Choose a reason for hiding this comment

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

Thanks @hurskiy-andriy. I didn't test this patch, if anyone else wants to checkout this PR and make a few extra checks before merging :)

@benmccann
Copy link
Contributor

I tested this locally. It mostly looks good. The one thing I would change is that I would remove week and quarter from interval. It's strange to have alignment on a week. E.g. I have an example that's aligning on July 2, 2017. I'm guessing that's the start of week 26 of the year or something, but really I want it aligned on July 1, 2017 since that's the start of the month.

@hurskiy-andriy
Copy link
Contributor Author

'week' and 'quarter' time units are prevented from determining as major units. Instead 'month' (if minor unit == 'day') or 'year' (if minor unit == 'month') unit will be determined as major.

@etimberg
Copy link
Member

So this is good to merge?

@benmccann
Copy link
Contributor

Thanks for the update @hurskiy-andriy

@etimberg @simonbrunel I think we should be good to merge this one now

@etimberg etimberg merged commit 2d7c1f0 into chartjs:master Jun 15, 2017
exwm pushed a commit to exwm/Chart.js that referenced this pull request Apr 30, 2021
Working towards creating the TimeSeries scale, this PR adds formatting for major and minor ticks on axes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants