Showing a duration of time within a Chart.js chart - javascript

I'm attempting to create a chart using Chart.JS for a project that will show the duration a device has been switched on for in a given day.
The dates are on the Y-axis with the X-axis containing a 24-hour time scale from 00:00 to 23:59 with horizontal bars expressing the time durations. I suppose I'm attempting to make something similar in style to a Gantt chart.
The Javascript code I have at the moment is this:
var timeAxis = [];
var dateAxis = [];
var startDate = moment('2000-01-01 00:00');
var endDate = moment('2000-01-01 23:59');
while (startDate <= endDate) {
timeAxis.push(startDate.format('HH:mm'));
startDate.add(1, 'minutes');
}
startDate = moment('2019-12-06');
endDate = moment('2019-12-13');
while (startDate <= endDate) {
dateAxis.push(startDate.format('ddd DD/MM'));
startDate.add(1, 'days');
}
var ctx = document.getElementById('deviceOnChart').getContext('2d');
var testChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
datasets: [{
label: 'Device On Time',
data: [
'2019-12-13 06:32',
'2019-12-12 09:26',
'2019-12-11 11:45',
'2019-12-10 18:06',
'2019-12-09 03:56',
'2019-12-08 15:34',
'2019-12-07 12:53',
'2019-12-06 21:35',
],
backgroundColor: 'rgba(0, 100, 0, 0.2)',
borderColor: 'rgba(0, 150, 0, 1)',
borderWidth: 0.5,
xAxisID: 'OnTime'
},
{
label: 'Device Off Time',
data: [
'2019-12-13 21:34',
'2019-12-12 17:28',
'2019-12-11 22:58',
'2019-12-10 21:45',
'2019-12-09 14:27',
'2019-12-08 19:35',
'2019-12-07 18:53',
'2019-12-06 22:35'
],
backgroundColor: 'rgba(100, 0, 0, 0.2)',
borderColor: 'rgba(150, 0, 0, 1)',
borderWidth: 0.5,
xAxisID: 'OffTime'
}]
},
options: {
scales: {
yAxes: [{
type: 'time',
time: {
unit: 'day',
parser: 'ddd DD/MM',
displayFormats: {
day: 'ddd DD/MM'
}
},
ticks: {
source: 'labels'
},
labels: dateAxis
}],
xAxes: [{
id: 'OnTime',
type: 'time',
time: {
unit: 'minute',
parser: 'HH:mm',
displayFormats: {
minute: 'HH:mm'
}
},
ticks: {
source: 'labels',
autoSkip: true
},
labels: timeAxis,
stacked: true
},
{
display: false,
id: 'OffTime',
type: 'time',
time: {
unit: 'minute',
parser: 'HH:mm',
displayFormats: {
minute: 'HH:mm'
}
},
ticks : {
source: 'labels',
autoSkip: true
},
labels: timeAxis,
stacked: true
}]
}
}
});
I have also created a JSFiddle to provide a demo of what the chart looks like at present (which is pretty bad). I've never really done much work with time axes in Chart.JS before so it's proving to be somewhat confusing for me and the documentation seems a little sparse in places.
I've been able to get the axes to display the dates and times correctly in what I am assuming is in a correct manner. However, I am uncertain as to how to correctly format the data such that Chart.JS can parse it. At the moment the chart is empty presumably because it doesn't know how to interpret the data I am trying to get it to display.
I have tried specifying the data as an array of objects with x and y attributes containing the time and date respectively. I have also tried putting it as a single dataset, as well as two datasets with the X-axis set as stacked and the chart just will not show anything.
Any help that anyone could provide would be much appreciated.

Here's my solution: https://jsfiddle.net/e6td4sh0/
I use the new floating-bar-feature from the quite new chart.js 2.9-version.
Everything works, except the timezone and the time format for the tooltip. I post the complete code here when I solved these problems. If somebody else solves them I would be glad if he/she updates my answer with the correct code.

Related

How to format x-axis based on how long between start and end time datepicker of data in chart.js?

Hello I am new to javascript. I have chart.js with the data from API look like this :
.....//datepicker code......
$.ajax({
method: "GET",
url: endpoint,
data: {
startDate: startDate,
endDate: endDate
},
success: function(data){
//get data by fields
var accelero_x = [], timestamp = [];
for (var i=0; i<data.length; i++){
accelero_x.push(data[i].accelero_x);
timestamp.push(data[i].timestamp);
}
//plot the chart
var ctx = document.getElementById("accelero_xChart").getContext('2d');
var accelero_xChart = new Chart(ctx, {
type: 'line',
data: {
labels: timestamp,
datasets: [{
label: 'accelero-x (mV/g)',
data: accelero_x,
backgroundColor: [
'#ff000000'
],
borderColor: [
'#331698'
],
pointBackgroundColor: '#331698',
borderCapStyle: 'round',
borderWidth: 3
}]
},
options: {
reponsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero:false,
stepSize:0.1
},
scaleLabel: {
display: true,
labelString: 'accelero-x (mV/g)'
}
}],
xAxes: [{
display: true,
type: "time",
time: {
min: moment(startDate).toDate(),//Date object type
max: moment(endDate).toDate()//Date object type
},
scaleLabel: {
display: true,
labelString: 'Time (hour)'
}
}]
}
}
});
},
error: function(error_data){
console.log(error_data)
}
});
My chart right now displaying the x-Axes per 2 hours. But I want different formats based on how long between the startDate and endDate time of data in the graph from the datepicker. If I choose more than two days between the startDate and endDate from datepicker, I want set format to show just date, not hours.
For example, when I choose the date from 7 May until 8 May, the x-Axes will be formatted into per 2 hours (HH:MM example: 01:00, 03:00, 05:00, and so on). But when I choose the date from 7 May until 9 May, the x-Axes will be formatted into date (ex: 7 May, 8 May, 9 May).
How can I do that?

How to plot date/time on X but display only dates in Chart.js?

I have a series of data points, each for a specific date/time. The time between each point varies, and the range covers several days (up to 30 days). There may be multiple points per day, or there may be days with no data points.
I would like the X scale to show the dates (with day of week), and for the data points to be plotted where they should go based on both the date and time of day. For instance, 2018-02-15 12:00:00 would be half-way between the labels for 02-15 and 02-16.
Here is some sample code/data:
var chartData = {
type:'line',
data: {
datasets: [
{
label:'Depression',
backgroundColor:'#00f',
borderColor:'#00f',
data:[
{y:3,t:Date.parse('2018/02/20 05:01:16')},
{y:4,t:Date.parse('2018/02/20 15:03:09')},
{y:5,t:Date.parse('2018/02/21 05:04:09')},
{y:1,t:Date.parse('2018/02/21 08:06:09')},
{y:5,t:Date.parse('2018/02/22 05:05:09')},
],
fill:false,
},
{
label:'Anxiety',
backgroundColor:'#d0d',
borderColor:'#d0d',
data:[
{y:6,t:Date.parse('2018/02/20 05:01:16')},
{y:2,t:Date.parse('2018/02/20 15:03:09')},
{y:4,t:Date.parse('2018/02/21 05:04:09')},
{y:6,t:Date.parse('2018/02/21 08:06:09')},
{y:3,t:Date.parse('2018/02/22 05:05:09')},
],
fill:false,
},
{
label:'Activity',
backgroundColor:'#f90',
borderColor:'#f90',
data:[
{y:4,t:Date.parse('2018/02/20 05:01:16')},
{y:1,t:Date.parse('2018/02/20 15:03:09')},
{y:4,t:Date.parse('2018/02/21 05:04:09')},
{y:7,t:Date.parse('2018/02/21 08:06:09')},
{y:3,t:Date.parse('2018/02/22 05:05:09')},
],
fill:true,
},
{
label:'Physical Health',
backgroundColor:'#ffc',
borderColor:'#cc0',
data:[
{y:-2,t:Date.parse('2018/02/20 05:01:16')},
{y:-3,t:Date.parse('2018/02/20 15:03:09')},
{y:-2,t:Date.parse('2018/02/21 05:04:09')},
{y:-6,t:Date.parse('2018/02/21 08:06:09')},
{y:-5,t:Date.parse('2018/02/22 05:05:09')},
],
fill:true,
},
],
fill:false,
},
'options': {
responsive:true,
title:{
display:true,
text:'Recent History',
},
scales: {
xAxes:[{
display:true,
time: {
min:Date.parse('2018/02/01 00:00:00'),
max:Date.parse('2018/03/01 00:00:00'),
displayFormats:{
day:'ddd MM/DD',
},
unit:'day',
round:'day',
},
distribution:'linear',
scaleLabel: {
display:true,
labelString:'Date'
},
bounds:'data',
ticks: {
source:'data',
},
}],
yAxes:[{
display:true,
scaleLabel:'Rating'
}]
},
}
};
The code above only displays the first two data points in each series.
Thanks!
http://www.chartjs.org/docs/latest/axes/cartesian/time.html#ticks-source
http://www.chartjs.org/docs/latest/axes/labelling.html#scale-title-configuration
You could try changing
ticks: {
source:'data',
},
... to source:'auto' which auto-truncates tick labels for you, and just see what that looks like ...
The time-scale display format for X-axis is described here, so you can format it to whatever Moment.js time format you want, e.g. 'YYYY-mm-dd:
xAxes: [{
type: 'time',
time: {
displayFormats: {
quarter: 'MMM YYYY'
}
}
}]
... Though it looks like maybe you have that in there already. Is it not showing any x-axis ticks? Is it showing any errors?
Or you could try following this example to override the callback method for a custom 'tick' if you want to include something besides the date/time. Their example was to append a dollar sign before all the values. If you only want to deal w/date-time then the above solution ought to be enough.

Why does Chartjs line chart does not animate to new values?

I am using a chartjs line chart showing time data where I want to update with new values from an ajax call.
I have time on the X axis (1 days on 15 minutes intervals) , and just numbers for the Y axis.
So it looks like the following..
My setup is as follows.
this.chartSetup = {
type: 'line',
data: {
labels: this.times,
datasets: [{
fill: true,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
label: title,
data: this.vals,
pointRadius: 0,
}]
},
options: {
spanGaps: true,
legend: {
position: 'bottom',
labels: {
boxWidth: 10
}
},
tooltips: {
enabled: false
},
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
ticks: {
stepSize: 6,
unitStepSize: 5
},
type: 'time',
time: {
displayFormats: {
hour: 'h:mm a',
minute: 'h:mm a',
}
}
}],
},
}
};
Chart.defaults.global.animation.easing = "easeOutBounce";
this.chart = new Chart(this.canvas.nativeElement, this.chartSetup);
When the chart first draws it animates the new values. However, if I then remove the data, and add a new set, it does not animate to the new values.
For example, to mimic new server data, using a timer, if I do the following,
where this.times holds the X data, this.vals holds the Y..
setTimeout(() => {
let temp = this.makeDummyData(20);
//let dataToUpdate = (<any>(this.chart.data)).datasets[0].data;
//let labels = (<any>(this.chart.data)).labels;
this.times.splice(0, this.times.length);
this.vals.splice(0, this.vals.length);
for (let item of temp) {
this.times.push(item.time);
this.vals.push(item.val);
}
this.chart.update();
}, 8000)
The chart does update, but it does not have any animation, it just jumps straight to the new display. If I just date the exiting data without removing it first, does does animate to the new display.
Is there any reason the animation does not work when I replace the data as in the above example?
Thanks in advance for any suggestions

Chartjs X axis label and tick formatting

I am using Chartjs to display a time series line graph.
My setup is as following...
this.chartSetup = {
type: 'line',
data: {
labels: this.times,
datasets: [{
fill: true,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
label: title,
data: this.vals,
pointRadius: 0,
}]
},
options: {
spanGaps: true,
legend: {
position: 'bottom',
labels: {
boxWidth: 10
}
},
tooltips: {
enabled: false
},
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [{
ticks: {
stepSize: 6,
unitStepSize: 5
},
type: 'time',
time: {
displayFormats: {
hour: 'h:mm a',
minute: 'h:mm a',
}
}
}],
},
}
};
Chart.defaults.global.animation.easing = "easeOutBounce";
this.chart = new Chart(this.canvas.nativeElement, this.chartSetup);
My chart looks like the following screen shot
The data is Date for the X axis (Labels), and just numbers for the Y.
The time data goes from 6am to 6pm (12 hours worth)
I have a couple of issues here all relating to the X axis label formatting.
The initial 6am label is being cut off
How can I change the X axis label rotation (so perhaps by 90 degrees will fix the truncated first value)
My data goes to 6pm, but it is showing an extra X axis value (7pm). Can I get rid of this?
Thanks in advance for any suggestions here.
What worked for me was setting
autoskip: true
autoSkipPadding: 30
in the tick configuration.
1,2 - set minRotation = 90
3 - set Max value on your x axes

Chartjs - Set start and end value into a Bar Chart

I am working on drowing a Gantt diagram like on Chartjs.
What am I trying to do is painting and HorizontalBarChart with time type, as a mixed type where I set a min value for each bar, however seems it does not work.
My code:
new Chart(document.getElementById("customChart"), {
type: 'horizontalBar',
data: {
labels: ['Item 1', 'Item 2'],
datasets: [
{
type: 'horizontalBar',
label: 'Bar Component1',
data: [new Date(2017,02,26) ],
options:{
scales:{
xAxes: [{
type: 'time',
unit: 'day',
unitStepSize: 1,
time: {
displayFormats: {
'day': 'YYYY-MM-DD'
},
min: new Date(2017,03,24)
}
}]
}
}
},
{
type: 'horizontalBar',
label: 'Bar Component2',
data: [new Date(2017,02,14)],
options:{
scales:{
xAxes: [{
type: 'time',
unit: 'day',
unitStepSize: 1,
time: {
displayFormats: {
'day': 'YYYY-MM-DD'
},
min: new Date(2017,02,10)
}
}]
}
}
}
]
}
});
Is there any workaround in order to implement this? Should I use another library?
Unfortunately, there is no way to configure chart.js to produce a gantt chart because each dataset that you plot on the graph either starts at the origin (the min value set on the scale) or is stacked right on top of each other. You cannot configure a chart to stack bars but show them in different "lanes" (which is what a gantt chart would require).
Even if you try to create multiple scales (which is looks like you are attempting), it will not work because the 2nd bar will still start at the origin (however the 2nd scale's origin would be the min value you specified). In other words, both bars will still touch the y axis.
You had several problems with you chart.js configuration. First, you cannot define scale config in a dataset. Second, you tried to use several time scale options, but they must be inside the time object.
I cleaned up everything just so you can see how to correctly define a chart. Here is a codepen demonstrating this.
Currently [November 2018] chart.js is not able todo so.
However if you are willing to apply a patch, there is a pull request pending, which would implement exactly this feature: https://github.com/chartjs/Chart.js/pull/5262
For my purposes I adapted the code of https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.bar.js
## -453,10 +453,12 ## module.exports = function(Chart) {
helpers.canvas.clipArea(chart.ctx, chart.chartArea);
- for (; i < ilen; ++i) {
- if (!isNaN(scale.getRightValue(dataset.data[i]))) {
- rects[i].draw();
- }
+ if (dataset.label != 'noshow') {
+ for (; i < ilen; ++i) {
+ if (!isNaN(scale.getRightValue(dataset.data[i]))) {
+ rects[i].draw();
+ }
+ }
}
helpers.canvas.unclipArea(chart.ctx);
Utilizing bar chart like this:
var gapdemo= new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: ["todo1", "todo2", "todo3", "todo4"],
datasets: [{
type: 'horizontalBar',
label: 'noshow',
data: [1,2,4,3],
},{
type: 'horizontalBar',
label: 'showme',
data: [3,2,2,1],
},{
type: 'horizontalBar',
label: 'noshow',
data: [1,5,3,4],
},{
type: 'horizontalBar',
label: 'showme',
data: [2,2,1,4],
}]
},
options: {
scales: {
xAxes: [{
id: 'x-axis-1',
stacked: true
}],
yAxes: [{
id: 'y-axis-1',
stacked: true,
ticks: {beginAtZero: true}
}]
}
}
});
This results in a chart like that:
barchart with gaps
Since version 2.9.0, Chart.js supports floating bars. Individual bars can now be specified with the syntax [min, max].
This makes it possible to draw a Gantt chart.
var dates = [new Date("2019-12-24"), new Date("2019-12-26"), new Date("2019-12-30"), new Date("2020-1-2"), new Date("2020-1-4"), new Date("2020-1-9"), new Date("2020-1-10") ];
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: dates.map((d, i) => "Task " + i).splice(1),
datasets: [
{
label: 'Tasks',
data: dates.map((d, i) => i == 0 ? null : [dates[i - 1], d]).slice(1),
backgroundColor: 'lightblue',
borderWidth: 1
}
]
},
options: {
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
day: 'YYYY-MM-DD'
}
},
ticks: {
min: dates[0].getTime(),
max: dates[dates.length - 1].getTime()
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.1.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart"></canvas>

Categories