Chart.js timeseries x ticks overlapping due to weekend - javascript

I use Chart.js to plot a line chart. My x axis is a timeseries.
However, I have ticks overlapping due to weekend data.
Is there any way to avoid overlapping ticks? I used "autoskip: true" but it doesn't seem to work.
Here's how my configs look like:
x: {
parsing: false,
type: "timeseries",
time: {
displayFormats: {
second: "HH:mm",
minute: "HH:mm",
hour: "HH:mm",
day: "MMM d",
},
tooltipFormat: "d MMM HH:mm",
},
grid: {
display: false,
},
ticks: {
autoskip: true,
},
},
And this is how the overlapping looks like:

You can achieve what you're looking for by writing a callback function that checks if the value is a weekend day
new Date(Date.parse(value)).getDay() == 1 || new Date(Date.parse(value)).getDay() == 2
If it is we just don't return it. Otherwise we return the value without changes.
This is how your config should look like:
x:{
type: 'timeseries'
time:{
unit:'day',
},
ticks:{
callback: function(value){
//if weekend dont return the tick label
if(new Date(Date.parse(value)).getDay() == 1 || new Date(Date.parse(value)).getDay() == 2 )
return
return value
}
}
}

Related

How can I group bars with same month in ChartJS?

I'm currently working on a chart where you can compare values from previous years with values from the current year.
Here is my code for the chart :
this.chart = new Chart(this.myChart.nativeElement, {
type: 'bar',
data: {
datasets: []
},
options: {
plugins: {
legend: {
display: false
},
tooltip: {
enabled: true,
callbacks: {
label: (tooltipItem: TooltipItem<any>): string | string[] => {
return `${tooltipItem.formattedValue} ${$localize`kWh`}`
},
}
}
},
scales: {
y: {
beginAtZero: true
},
x: {
adapters: {
date: {
locale: 'fr-FR',
zone: 'Europe/Paris'
}
},
ticks: {
source: 'labels',
},
display: true,
type: 'time',
time: {
unit: 'month',
displayFormats: {
month: 'MMM',
day: 'dd MMMM',
week: 'WW-yy'
},
tooltipFormat: { month: 'long', year: '2-digit' }
}
},
},
transitions: {
show: {
animation: {
duration: 0
}
},
hide: {
animation: {
duration: 0
}
}
}
}
});
Then I give my datasets to the chart this way :
initChartData() {
this.chart.data.labels = this.dataObject.datas.map(c => c.startDate)
this.chart.data.datasets[0] = {
data: this.dataObject.datas.map(c => ({ x: c.startDate.toString(), y: c.data })) as any,
backgroundColor: '#58c0d8',
borderColor: '#58c0d8',
}
this.chart.update();
}
I give the data as an object, so my tooltip has the correct date, because it is formatted via the time options i previously gave to the chart.
The problem is that, as I give the data in this way to the chart, the chart cannot superimpose the two set of bars and it gives me a result like this :
If I stop furnishing the data as an object, giving only the value, it gives a result almost good, like this :
but as you can see if I hover the second bar :
it will give my the exact same month, from the same year, which is not the desired behavior. I completly understand why it is doing this, because as i dont give it any personnal label, the bar tooltip can't know his year, so as for me the only solution was to give the data as an object, but i can't make it work with the data side by side.
I've been struggling for two days now with this so I really hope someone can help me out, and I want to thanks anyone who will try in advance !

Hide specific x axis **labels** in Chartjs

I would like to hide specific x axis labels that are less than moment().valueOf(). So If I have 12:40, 12:45, 12:50 and 12:55 is the current time then I want to display 12:55 and hide the past time interval labels. Key here is to only hide the labels not get rid of the them.
My chart max x-axis time is always present time and increases as you pan right.
I've managed to get filtered ticks time as an array ["12:55"] but the chart still shows all the other time before 12:55 .
My xAxis configuration
xAxes: [
{
xAxisID: 'x-1',
type: "time",
time: {
unit: "minute",
displayFormats: { minute: 'HH:mm' },
stepSize: 5,
min: chartMin,
max: chartDisplayMax,
},
afterBuildTicks: function (axis) {
const { ticks } = axis;
const ticksToDisplay= ticks && ticks.filter(tick => tick >= moment().subtract(5, "minutes").format('HH:mm'));
return ticksToDisplay;
},
ticks: {
display: true,
},
},
],

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?

Showing a duration of time within a Chart.js chart

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.

Highstock compare previous data point when date does not exist in series

I am using highstock to show fund data in a line graph, the data series I am using is missing dates (weekends mostly). I have no control over the source code of the data series, though I have formatted it by looping through it in JS so it can be used with Highstock. The problem occurs when I use the rangeSelector on missing dates, when I choose From in the range selector to a weekend date (a date that is missing in the data series) the compare percentage starts calculating from the next available data point.
Example
Go to this demo: http://www.highcharts.com/stock/demo/compare
Choose 14 dec, 2014 as the From date.
The calculation starts from 2014-12-15 as the 0 value, which is a monday. I want it to always start the compare percentage at the previous data point, not the next. I would want it to start from 2014-12-12 which is a friday.
How I initiate highstocks in JS:
var opts = {
chart : {
backgroundColor: '#f9f9fa',
borderWidth: 0,
type: 'line'
},
rangeSelector : {
buttons: [{
type: 'month',
count: 3,
text: '3m'
}, {
type: 'month',
count: 6,
text: '6m'
}, {
type: 'ytd',
text: 'YTD'
}, {
type: 'year',
count: 1,
text: '1y'
}, {
type: 'all',
text: 'All'
}],
selected : 3,
inputEnabled: false
},
plotOptions: {
series: {
compare: 'percent'
}
},
title : {
text : ''
},
navigator : {
enabled : false
},
credits: {
enabled: false
},
series : [{
name : '',
data : seriesData,
lineColor : '#002855',
tooltip: {
valueDecimals: 4
},
turboThreshold : 0
}],
xAxis : {
dateTimeLabelFormats: {
millisecond: '%H:%M:%S.%L',
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%e %b.',
week: '%b %y',
month: '%b %y',
year: '%Y'
},
ordinal: false,
minTickInterval : 4 * 7 * 24 * 3600 * 1000
},
yAxis : {
labels: {
format: '{value} %'
}
},
tooltip : {
valueSuffix : '',
pointFormat : '<span style="color:{point.color}">\u25CF</span> {point.y} SEK ({point.change}%)<br/>'
}
};
$(el).highcharts('StockChart', opts);
My seriesData var looks like this after I have formatted it for use in Highstock:
[
{ name="2005-01-03", x=1104710400000, y=100 },
{ name="2005-01-04", x=1104796800000, y=99.9983 },
{ name="2005-01-05", x=1104883200000, y=99.9175014 },
{ name="2005-01-07", x=1105056000000, y=100.0739722 },
// This continues to the current date
]
x is a timestamp.
y is the stock value
name is a string representing the timestamp in x
el is defined before, and is a element node object.
Is it possible to make the compare start at the previous available data point and not the next when a date in the data series does not exist?
Any help regarding this issue will be appreciated!
Edit: Added my solution as an answer below
I found afterSetExtremes very useful to modify min and max, I check if the date is a saturday or sunday. If its a saturday I go -1 day back in time, if its a sunday I go -2 days back in time. This should cover all normal weekends for me, and it works quite good. Though it wont cover holidays that occur on weekdays. I also do not modify the max time, though I might need to do that.
My current xAxis:
xAxis : {
events: {
afterSetExtremes: function(e){
var maxTimestamp = this.max,
minTimestamp = this.min;
var dateMin = new Date( minTimestamp ),
dateMax = new Date( maxTimestamp ),
minDayOfTheWeek = dateMin.getDay();
// Test to see if its saturday or sunday
if( minDayOfTheWeek === 6 || minDayOfTheWeek === 0 ){
if( minDayOfTheWeek === 6 ){
dateMin.setDate( dateMin.getDate() - 1 );
}else if( minDayOfTheWeek === 0 ){
dateMin.setDate( dateMin.getDate() - 2 );
}
this.setExtremes( dateMin.getTime(), dateMax.getTime() );
}
}
},
dateTimeLabelFormats: {
millisecond: '%H:%M:%S.%L',
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%e %b.',
week: '%b %y',
month: '%b %y',
year: '%Y'
},
ordinal: false,
minTickInterval : 4 * 7 * 24 * 3600 * 1000
}
And added this to the chart cause afterSetExtremes do not run on load for me:
chart : {
backgroundColor: '#f9f9fa',
borderWidth: 0,
events:{
load: function(){
var max = this.xAxis[0].max,
min = this.xAxis[0].min;
this.xAxis[0].setExtremes( min, max );
}
},
type: 'line'
}

Categories