Reputation: 67
I am trying to represent 24 hours data of each Weekday in a Month in a Multi-Line Google Chart.
If I set the data normally in ChartWrapper without the custom view, then it creates gaps between consecutive months as the data would be there only for 24 hours of a single day for each month. So far I have been able to represent it as per requirement on the main ChartWrapper with a custom view(as string) but haven't been able to set the same view in the ControlWrapper as it doesn't allow string type in the view. The timestamp format used here (MM yy HH:mm) is not a regular one.
Sample Chart Data-
var data = [
["Date", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
[new Date("2019-09-01T12:25:00.000Z"), 0, 0, 0, 0, 0, 0, 0],
[new Date("2019-09-01T12:20:00.000Z"), 0, 0, 0, 0, 0, 0, 0],
[new Date("2019-09-01T12:30:00.000Z"), 0, 2, 0, 0, 0, 0, 0],
[new Date("2019-10-30T00:00:00.000Z"), 0, 1, 0, 0, 0, 0, 0],
[new Date("2019-10-30T00:05:00.000Z"), 0, 2, 0, 0, 0, 0, 0],
[new Date("2019-10-30T00:10:00.000Z"), 0, 7, 0, 0, 0, 0, 0],
[new Date("2019-10-30T12:50:00.000Z"), 0, 5, 0, 0, 0, 0, 0],
[new Date("2019-11-01T12:55:00.000Z"), 0, 0, 0, 0, 0, 0, 0],
[new Date("2019-11-01T14:00:00.000Z"), 0, 5, 0, 0, 0, 0, 0],
[new Date("2019-11-01T14:05:00.000Z"), 0, 4, 0, 0, 0, 0, 0],
[new Date("2019-11-01T14:10:00.000Z"), 0, 2, 0, 0, 0, 0, 0],
[new Date("2019-11-01T14:15:00.000Z"), 0, 8, 0, 0, 0, 0, 0],
[new Date("2019-11-01T14:20:00.000Z"), 0, 2, 0, 0, 0, 0, 0]]
Custom view for ChartWrapper-
var formatDate = new google.visualization.DateFormat({
pattern: 'MMM yy'
});
var formatMonth = new google.visualization.DateFormat({
pattern: 'MMM'
});
var formatTime = new google.visualization.DateFormat({
pattern: 'HH:mm'
});
var view = new google.visualization.DataView(chart_data);
view.setColumns([{
calc: function(dt, row) {
var rowDate1 = formatDate.formatValue(dt.getValue(row, 0));
var rowDate2 = null;
if (row > 0) {
rowDate2 = formatDate.formatValue(dt.getValue(row - 1, 0));
}
if (rowDate1 === rowDate2) {
rowDate1 = formatMonth.formatValue(dt.getValue(row, 0)) + ' ' + formatTime.formatValue(dt.getValue(row - 1, 0));
}
return rowDate1;
},
label: chart_data.getColumnLabel(0),
type: 'string'
}, 1, 2, 3, 4, 5, 6, 7]);
Code link: https://jsfiddle.net/namangupta/9ghfLx51/35/
What I want is basically to represent the data on the ControlWrapper as it is shown on the ChartWrapper without the gaps in-between the months.
Upvotes: 1
Views: 561
Reputation: 61230
as you've found, the range filter will only work on a continuous axis (number, date, etc...)
to correct this issue, and still display the custom date format in the chart's tooltips,
we'll change the view column for the x-axis.
to keep it simple, we'll use the data table row index as the x-axis value.
this will get us the continuous axis we need.
and we'll set the formatted value to the custom date format.
return {v: row, f: rowDate1}; // <-- set both value and formatted value
the view column...
calc: function(dt, row) {
var rowDate1 = formatDate.formatValue(dt.getValue(row, 0));
var rowDate2 = null;
if (row > 0) {
rowDate2 = formatDate.formatValue(dt.getValue(row - 1, 0));
}
if (rowDate1 === rowDate2) {
rowDate1 = formatMonth.formatValue(dt.getValue(row, 0)) + ' ' + formatTime.formatValue(dt.getValue(row - 1, 0));
}
return {v: row, f: rowDate1}; // <-- set both value and formatted value
},
we'll use the view to set the min / max values on the range filter...
var dateRange = view.getColumnRange(0);
var mindate = dateRange.min;
var maxdate = dateRange.max;
and draw the dashboard using the view...
// draw the dashboard
dash.draw(view);
see working fiddle...
https://jsfiddle.net/WhiteHat/9kceva14/1/
note: in the fiddle you posted, google charts is being loaded twice. only need one load statement, see above fiddle...
EDIT
to format the x-axis labels, we can use the same approach,
by providing both the value (v:
) and the formatted value (f:
),
using option --> ticks
however, this does mean we have to build the ticks manually.
so you will have to come up with the algorithm that displays the desired number of labels.
in this example, I've used the same function for the calculated column on the data view.
I've named the function, and re-used it for the chart ticks.
for the control, I only use the month name, when it changes.
however, the first month name does not appear.
I'm guessing there just isn't room. May need to use dates from the middle of the month or something.
var view = new google.visualization.DataView(chart_data);
view.setColumns([{
calc: formatAxis,
label: chart_data.getColumnLabel(0),
type: 'number'
}, 1, 2, 3, 4, 5, 6, 7]);
var ticksChart = [];
var ticksControl = [];
var monthTick;
var monthName = null;
for (var i = 0; i < chart_data.getNumberOfRows(); i++) {
// chart ticks
ticksChart.push(formatAxis(chart_data, i));
// control ticks
monthTick = formatMonth.formatValue(chart_data.getValue(i, 0));
if (monthTick !== monthName) {
monthName = monthTick;
ticksControl.push({v: i, f: monthName});
}
}
function formatAxis(dt, row) {
var rowDate1 = formatDate.formatValue(dt.getValue(row, 0));
var rowDate2 = null;
if (row > 0) {
rowDate2 = formatDate.formatValue(dt.getValue(row - 1, 0));
}
if (rowDate1 === rowDate2) {
rowDate1 = formatMonth.formatValue(dt.getValue(row, 0)) + ' ' + formatTime.formatValue(dt.getValue(row - 1, 0));
}
return {v: row, f: rowDate1};
}
see ticks
option on chart and control, e.g.
hAxis: {
textStyle: {
color: '#ffffff',
},
ticks: ticksControl
}
see following working fiddle...
https://jsfiddle.net/WhiteHat/9kceva14/3/
EDIT 2
since we're essentially hard-coding the x-axis labels,
the chart's x-axis range doesn't change dynamically, as we drag the range filter handles.
to address this issue, we can listen for the 'statechange'
event on the range filter,
get the state of the filter, and adjust the viewWindow
option on the chart.
this will adjust the visible range on the chart as the range filter changes.
whenever we change the chart's options or data,
we must also re-draw the chart for the change to take effect.
google.visualization.events.addListener(rangeFilter, 'statechange', onStateChange);
function onStateChange() {
var filterState = rangeFilter.getState();
chart.setOption('hAxis.viewWindow', {
min: filterState.range.start,
max: filterState.range.end
});
chart.draw();
}
see following working fiddle...
https://jsfiddle.net/WhiteHat/9kceva14/5/
Upvotes: 1