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

Timeseries scale #4364

Closed
wants to merge 7 commits into from
Closed

Conversation

IlyaBeliaev
Copy link

Timeseries scale added, see this issue for more info: #4189

small example here: https://codepen.io/ilyabelyaev/pen/BRvKPw

@etimberg
Copy link
Member

@IlyaBeliaev I haven't had a chance to look at this in detail yet, but could you rebase this against master?

<script src="../../../dist/Chart.js"></script>
<script src="../../utils.js"></script>
<style>
canvas {
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like there's some indentation here that should be switched from spaces to tabs

Copy link
Author

Choose a reason for hiding this comment

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

ok

<script src="../../../dist/Chart.js"></script>
<script src="../../utils.js"></script>
<style>
canvas {
Copy link
Contributor

Choose a reason for hiding this comment

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

spaces vs tabs

Copy link
Author

Choose a reason for hiding this comment

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

ok

allTimestamps = allTimestamps.concat(value);
});

allTimestamps = arrayUnique(allTimestamps).sort(function(a, b) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure we should sort here. I would expect the user to pass the data points in sorted already. If they want to plot in reverse chronological order we should probably let them do that, but sorting would stop that from working

Copy link
Member

Choose a reason for hiding this comment

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

Agreed, we shouldn't sort since.

Copy link
Author

Choose a reason for hiding this comment

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

I guess we should add some config option to allow users to make reverse order. I can't build ticks without sorting here. Because there are a data from all datasets.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe for the time series scale we can just say that scatter is not supported?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I'm fine saying scatter is not supported


## Date Formats

When providing data for the time scale, Chart.js supports all of the formats that Moment.js accepts. See [Moment.js docs](http://momentjs.com/docs/#/parsing/) for details.
Copy link
Contributor

Choose a reason for hiding this comment

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

"time scale" -> "timeseries scale"

Copy link
Author

Choose a reason for hiding this comment

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

ok

data: data,
options: {
scales: {
xAxes: [{
Copy link
Member

Choose a reason for hiding this comment

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

we should add the type option here to the x axis config

Copy link
Author

Choose a reason for hiding this comment

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

ok

Copy link
Author

Choose a reason for hiding this comment

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

done

// Get tooltip label
getLabelForIndex: function(index, datasetIndex) {
var me = this;
var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
Copy link
Member

Choose a reason for hiding this comment

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

[nit] me.chart.data is used a couple of times here. I think we should capture it in a local variable for improved minification

Copy link
Author

Choose a reason for hiding this comment

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

ok

Copy link
Author

Choose a reason for hiding this comment

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

done


time: {
parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
Copy link
Member

Choose a reason for hiding this comment

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

do we need to provide this option since it's deprecated?

Copy link
Author

Choose a reason for hiding this comment

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

Hm, It looks like both options have no effect on time series. So I can remove them.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good

Copy link
Author

Choose a reason for hiding this comment

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

Format is used in helpers.time and it should be removed from both scales at one time.

format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
unit: false, // false == automatic or override with week, month, year, etc.
round: false, // none, or override with week, month, year, etc.
displayFormat: false, // DEPRECATED
Copy link
Member

Choose a reason for hiding this comment

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

same with this option?

Copy link
Author

Choose a reason for hiding this comment

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

removed.

return value;
},
getBasePixel: function() {
return this.bottom;
Copy link
Member

Choose a reason for hiding this comment

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

what will this do for horizontal bar charts using the timeseries axis as the y axis?

Copy link
Author

Choose a reason for hiding this comment

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

It works only on x axis same as time scale.

@IlyaBeliaev IlyaBeliaev force-pushed the timeseries-scale branch 2 times, most recently from 23d57fd to 6b9c919 Compare June 28, 2017 11:52
@etimberg
Copy link
Member

etimberg commented Jul 3, 2017

I think this is ready to be merged (other than the conflict in src/chart.js)

@IlyaBeliaev
Copy link
Author

it's good! made rebase

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.

A few feedback.

Wondering if since timeseries is closer to the category logic, why not inheriting category instead of timebase, and have time manipulation method as helpers?

@@ -0,0 +1,94 @@
# TimeSeries Cartesian Axis
Copy link
Member

Choose a reason for hiding this comment

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

Could we find a way to avoid this doc duplication: maybe merge both in the same page (docs/axes/cartesian/time.md) with a special section about the TimeSeries listing differences? or a common page for time base scales?

Copy link
Author

Choose a reason for hiding this comment

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

added timeseries description into time.md

@@ -117,6 +117,18 @@
path: 'scales/time/combo.html'
}]
}, {
title: 'TimeSeries scale',
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure we need to duplicate the 3 examples, maybe 1 is enough and could be added to the Time Scale group at the end (title: Series (TimeSeries Scale)).

Copy link
Contributor

Choose a reason for hiding this comment

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

A single example would be fine with me. I would just suggest that we not use the combo chart as the example in that case. We were also talking about following up afterwards in a separate PR with some improvements to the time samples. E.g. make the samples show more points by default and add a dropdown which lets you see samples with minutes, hours, weeks, months, etc. instead of just days

Copy link
Author

Choose a reason for hiding this comment

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

done


return label;
},
// Function to format an individual tick mark
Copy link
Member

Choose a reason for hiding this comment

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

Indentation++

Copy link
Author

Choose a reason for hiding this comment

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

done

var label = chartData.labels && index < chartData.labels.length ? chartData.labels[index] : '';
var value = chartData.datasets[datasetIndex].data[index];

if (value !== null && typeof value === 'object') {
Copy link
Member

Choose a reason for hiding this comment

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

if(helpers.isObject(value))

Copy link
Author

Choose a reason for hiding this comment

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

done


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

if (callback) {
Copy link
Member

Choose a reason for hiding this comment

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

return {
     value: callback? callback(formattedTick, index, ticks) : formattedTick,
     major: major
 };

Copy link
Author

Choose a reason for hiding this comment

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

done

convertTicksToLabels: function() {
var me = this;
me.ticksAsTimestamps = me.ticks;
me.ticks = me.ticks.map(function(tick) {
Copy link
Member

Choose a reason for hiding this comment

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

me.ticks = me.ticks.map(moment).map(me.tickFormatFunction, me);

Copy link
Author

Choose a reason for hiding this comment

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

it's not possible here because moment has constructor with multiple params. See https://momentjs.com/docs/#/parsing/string-formats/

Copy link
Member

Choose a reason for hiding this comment

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

Might be good to add a comment or even better, change it for a vanilla for loop and avoid doubling function calls?

getLabelCapacity: function(exampleTime) {
var me = this;

me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
Copy link
Member

Choose a reason for hiding this comment

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

Move that line after all var to help minification

Copy link
Author

Choose a reason for hiding this comment

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

me.displayFormat used inside me.tickFormatFunction which is called on a next line

Copy link
Member

Choose a reason for hiding this comment

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

Not obvious :\

minUnit: 'millisecond',

// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
displayFormats: {
Copy link
Member

Choose a reason for hiding this comment

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

We should really find a way to avoid these options duplication (not sure how though) since both scales inherit the same base time scale, so would make sense to have common options in the base class as well.

Copy link
Author

Choose a reason for hiding this comment

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

Now time and timeseries scale has different displayFormats because timeseries scale does not support tick alignment and major units yet. I'm working on the next PR that adds this functionality to the timeseries scale. There display formats will be same for both scales and then I can move it to helpers.time.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good!


if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null && me.chart.isDatasetVisible(datasetIndex)) {
// We have potential point data, so we need to parse this
helpers.each(dataset.data, function(value, dataIndex) {
Copy link
Member

Choose a reason for hiding this comment

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

We should avoid as much as possible to use function based iterations, it's a perf killer especially when iterating lot of data.

Copy link
Author

Choose a reason for hiding this comment

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

replaced with vanilla js loops

@simonbrunel
Copy link
Member

Also curious how many KB this PR introduces compared to the master Chart.min.js size?

@benmccann
Copy link
Contributor

Yeah, timeseries is conceptually part time / part category However, it turns out that it's quite hard to share much code with category. I tried that first I believe, but there were only a few methods that were generally the same and even they had subtle differences that made sharing hard. I think inheriting from time is actually the better way to go as it cuts down more on the amount of code required.

@IlyaBeliaev
Copy link
Author

Sizes: 155 734 bytes vs 153 051 bytes

@IlyaBeliaev
Copy link
Author

About a code from category scale. I'm working on the next PR that will add support of tick alignment and major units for timeseries scale. There timeseries scale have an other code to determine tick positions etc. So it was a good decision to inherit it from time scale.

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 @IlyaBeliaev for the updates. Just added a few more feedback that I think should be changed before merging.

There is still some pieces of code I didn't report but would be great to change for performance, minification and readability but I guess I'm too picky and don't want to keep this PR open forever.

Edit: actually, these changes mostly concern the existing code in master you refactored in timebase.

@@ -105,7 +105,7 @@
path: 'scales/logarithmic/scatter.html'
}]
}, {
title: 'Time scale',
title: 'Time and TimeSeries scale',
Copy link
Member

Choose a reason for hiding this comment

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

Can we keep title: 'Time scales' and avoid the title on 2 lines?

image

Copy link
Author

Choose a reason for hiding this comment

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

done

@@ -39,7 +38,7 @@ module.exports = function(Chart) {
}
};

var TimeScale = Chart.Scale.extend({
var TimeScale = Chart.TimeScaleBase.extend({
initialize: function() {
Copy link
Member

Choose a reason for hiding this comment

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

I think this initialize override needs to be removed (looks exactly the same as the one in TimeScaleBase).

Copy link
Author

Choose a reason for hiding this comment

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

yep

minUnit: 'millisecond',

// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
displayFormats: {
Copy link
Member

Choose a reason for hiding this comment

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

Sounds good!

convertTicksToLabels: function() {
var me = this;
me.ticksAsTimestamps = me.ticks;
me.ticks = me.ticks.map(function(tick) {
Copy link
Member

Choose a reason for hiding this comment

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

Might be good to add a comment or even better, change it for a vanilla for loop and avoid doubling function calls?

getLabelCapacity: function(exampleTime) {
var me = this;

me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
Copy link
Member

Choose a reason for hiding this comment

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

Not obvious :\

@IlyaBeliaev
Copy link
Author

@simonbrunel Thank you for the review. I think I can refactor timebase a bit in a next PR.

simonbrunel
simonbrunel previously approved these changes Jul 11, 2017
},
},
ticks: {
autoSkip: true
Copy link
Contributor

Choose a reason for hiding this comment

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

@IlyaBeliaev comment from @simonbrunel :

I see you turn autoSkip back to true for the timeseries? actually, that's my (hopefully) last issue: since the time scale doesn't support autoSkip, it's false by default, so can't have the same default as your PR (true)

I wasn't sure why you needed to do this as I had it set to false in the original code: https://github.com/chartjs/chartjs-chart-financial/blob/master/src/scale.timeseries.js#L85

Is this something you can change back to false?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants