Related
Following there are 2 examples of google charts code. The only difference in the last example is the start second. Does anybody know, why I get "cannot read property 'length' of null" in the last example? Also if I shorten the name of row 2 and 3 from "Second Test entry number 2" to a shorter, the chart is displayed.
Working: https://jsfiddle.net/5rotomyc/
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Group' });
dataTable.addColumn({ type: 'string', id: 'Role' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
['First', null, new Date(2017,1,15, 22, 40, 27), new Date(2017,10,29, 23, 59, 59)],
['Second Test entry number 2', null, new Date(2017,8,4, 0, 0, 0), new Date(2018,0,16, 23, 59, 59)],
['Second Test entry number 2', null, new Date(2018,0,25, 0, 0, 0), new Date(2018,1,06, 23, 59, 59)]
]);
chart.draw(dataTable);
}
Second example which is not working https://jsfiddle.net/ypz095g9/:
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Group' });
dataTable.addColumn({ type: 'string', id: 'Role' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
['First', null, new Date(2017,1,15, 22, 40, 26), new Date(2017,10,29, 23, 59, 59)],
['Second Test entry number 2', null, new Date(2017,8,4, 0, 0, 0), new Date(2018,0,16, 23, 59, 59)],
['Second Test entry number 2', null, new Date(2018,0,25, 0, 0, 0), new Date(2018,1,06, 23, 59, 59)]
]);
chart.draw(dataTable);
}
I'm getting desperate right here. hope somebody can help with this bug. Thank you.
looks like a problem with addRows
seen weird stuff happen when an entire column only has null values
(the code actually works for me as-is in chrome)
the 'Role' column is optional, you can remove it...
see following working snippet...
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Group' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
['First', new Date(2017,1,15, 22, 40, 26), new Date(2017,10,29, 23, 59, 59)],
['Second Test entry number 2', new Date(2017,8,4, 0, 0, 0), new Date(2018,0,16, 23, 59, 59)],
['Second Test entry number 2', new Date(2018,0,25, 0, 0, 0), new Date(2018,1,06, 23, 59, 59)]
]);
chart.draw(dataTable);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>
or use a blank string '' instead...
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Group' });
dataTable.addColumn({ type: 'string', id: 'Role' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
['First', '', new Date(2017,1,15, 22, 40, 26), new Date(2017,10,29, 23, 59, 59)],
['Second Test entry number 2', '', new Date(2017,8,4, 0, 0, 0), new Date(2018,0,16, 23, 59, 59)],
['Second Test entry number 2', '', new Date(2018,0,25, 0, 0, 0), new Date(2018,1,06, 23, 59, 59)]
]);
chart.draw(dataTable);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>
To change the point size, I set pointsize to 10 (for example).
options: {
pointSize: 10,
}
I would like to add a border to this point. Any idea ?
using a data view, you can apply a style to all the rows using a column role...
here, the view will include columns 0, 1 from the data,
and add a third calculated column for the style...
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: function (dt, row) {
return 'point {stroke-color: #F00; stroke-width: 2;}';
},
role: 'style',
type: 'string'
}]);
then you must use the view when drawing the dashboard...
dashboard.draw(view);
see following working snippet...
google.charts.load('current', {packages: ['corechart', 'controls'],'language': 'fr'});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1AOVg0jYaDvoHQeXBcDtJ6HdkBkkcQhEBi9Xo_crOvlk/edit?usp=sharing');
query.send(drawDashboard);
}
function drawDashboard(response) {
var data = response.getDataTable();
var chart = new google.visualization.ChartWrapper({
chartType: 'AreaChart',
containerId: 'chart_div',
options: {
// width and chartArea.width should be the same for the filter and chart
height: 400,
colors: ['#4aadde'],
curveType: 'function',
pointSize: 5,
chartArea: {
width: '75%'
},
title: 'Company Performance',
hAxis: {title: 'Year', titleTextStyle: {color: '#333'},format: 'd MMM yyyy' },
vAxis: {minValue: 0}
}
});
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: function (dt, row) {
return 'point {stroke-color: #F00; stroke-width: 2;}';
},
role: 'style',
type: 'string'
}]);
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control_div',
options: {
filterColumnIndex: 0,
ui: {
'chartType': 'AreaChart',
chartOptions: {
height: 50,
areaOpacity: 0.9,
colors: ['#5dade0'],
chartArea: {
width: '75%'
}
},
minRangeSize: 86400000, // 86400000ms = 1 day
snapToData: true
}
},
state: {
range: {
// set the starting range to January 2012
start: new Date(2017, 05, 15),
}
}
});
var dashboard = new google.visualization.Dashboard(document.querySelector('#dashboard_div'));
dashboard.bind([control], [chart]);
dashboard.draw(view);
function zoomLastDay () {
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth(), range.max.getDate() - 1),
end: range.max
}
});
control.draw();
}
function zoomLastWeek () {
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth(), range.max.getDate() - 7),
end: range.max
}
});
control.draw();
}
function zoomLastMonth () {
// zoom here sets the month back 1, which can have odd effects when the last month has more days than the previous month
// eg: if the last day is March 31, then zooming last month will give a range of March 3 - March 31, as this sets the start date to February 31, which doesn't exist
// you can tweak this to make it function differently if you want
var range = data.getColumnRange(0);
control.setState({
range: {
start: new Date(range.max.getFullYear(), range.max.getMonth() - 1, range.max.getDate()),
end: range.max
}
});
control.draw();
}
var runOnce = google.visualization.events.addListener(dashboard, 'ready', function () {
google.visualization.events.removeListener(runOnce);
if (document.addEventListener) {
document.querySelector('#lastDay').addEventListener('click', zoomLastDay);
document.querySelector('#lastWeek').addEventListener('click', zoomLastWeek);
document.querySelector('#lastMonth').addEventListener('click', zoomLastMonth);
}
else if (document.attachEvent) {
document.querySelector('#lastDay').attachEvent('onclick', zoomLastDay);
document.querySelector('#lastWeek').attachEvent('onclick', zoomLastWeek);
document.querySelector('#lastMonth').attachEvent('onclick', zoomLastMonth);
}
else {
document.querySelector('#lastDay').onclick = zoomLastDay;
document.querySelector('#lastWeek').onclick = zoomLastWeek;
document.querySelector('#lastMonth').onclick = zoomLastMonth;
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_div">
<input id="lastDay" type="button" value="Hier" />
<input id="lastWeek" type="button" value="Dernière semaine" />
<input id="lastMonth" type="button" value="Dernier mois" />
<div id="chart_div"></div>
<div id="control_div"></div>
</div>
note: the following line (last in the fiddle) is for the old jsapi library
it isn't needed and should be removed...
google.load('visualization', '1', {packages:['controls'], callback: drawChart});
When a chart is drawn, it scrolls to the top but I am trying to make the chart stay on the same place at redraw. Because I cannot see the source code, I tried to get the scroll position and scroll to it on redraw but it does not work. Can someone please help me or is there a better way of doing it. Thank you.
<div class="row">
<div class="col-12">
<div id="timelineDiv">
<div class="text-center">
<p class="mes">{{timelinecontr.mess}}</p>
</div>
<div class="col-12">
<div id="timeline" class="chart"></div>
</div>
</div>
</div>
</div>
#timelineDiv{
overflow-x: scroll;
overflow-y: scroll;
white-space: nowrap;
border: 13px solid #bed5cd;
width: 100%;
margin: 0 auto;
position: relative;
background-color: deepskyblue;
height: 550px;
}
timelinecontr.pos = $('#timeline div').scrollTop(); // position
$('#timeline div').scrollTop(timelinecontr.pos) // this is called on chart redraw
need to wait until the chart has finished drawing before setting the scroll position
before drawing the chart, get the scroll position
when the chart's 'ready' event fires, set the scroll position
var rowHeight = 42;
var timelinePos;
google.visualization.events.addListener(chart, 'ready', function () {
$('#timeline').scrollTop(timelinePos);
});
function drawChart() {
timelinePos = $('#timeline').scrollTop();
chart.draw(dataTable, {
height: (dataTable.getNumberOfRows() * rowHeight) + rowHeight
});
}
note: if no height option is set on the chart, the timeline will use its own scrollbar
see following working snippet...
google.charts.load('current', {
callback: function () {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Room' });
dataTable.addColumn({ type: 'string', id: 'Name' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ '1', 'A', new Date(2011, 3, 30), new Date(2012, 2, 4) ],
[ '2', 'B', new Date(2012, 2, 4), new Date(2013, 3, 30) ],
[ '3', 'C', new Date(2013, 3, 30), new Date(2014, 2, 4) ],
[ '4', 'D', new Date(2014, 2, 4), new Date(2015, 2, 4) ],
[ '5', 'E', new Date(2015, 3, 30), new Date(2016, 2, 4) ],
[ '6', 'F', new Date(2016, 2, 4), new Date(2017, 2, 4) ],
[ '7', 'G', new Date(2017, 2, 4), new Date(2018, 2, 4) ],
[ '8', 'H', new Date(2018, 2, 4), new Date(2019, 2, 4) ],
[ '9', 'I', new Date(2019, 2, 4), new Date(2020, 2, 4) ],
[ '0', 'J', new Date(2020, 2, 4), new Date(2021, 2, 4) ]
]);
var rowHeight = 42;
var timelinePos;
google.visualization.events.addListener(chart, 'ready', function () {
$('#timeline').scrollTop(timelinePos);
});
function drawChart() {
timelinePos = $('#timeline').scrollTop();
chart.draw(dataTable, {
height: (dataTable.getNumberOfRows() * rowHeight) + rowHeight
});
}
$('#draw-chart').on('click', drawChart);
$(window).resize(drawChart);
drawChart();
},
packages: ['timeline']
});
#timeline {
overflow-x: scroll;
overflow-y: scroll;
white-space: nowrap;
border: 13px solid #bed5cd;
width: 100%;
margin: 0 auto;
position: relative;
background-color: deepskyblue;
height: 350px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>
<button id="draw-chart">Draw Chart</button>
i'm trying to use Google Chart API for building an Waterfall chart. I noticed that Candlestick/Waterfall charts are not supporting the annotations.
See this jsfiddle sample
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Category');
data.addColumn('number', 'MinimumLevel');
data.addColumn('number', 'MinimumLevel1');
data.addColumn('number', 'MaximumLevel');
data.addColumn('number', 'MaximumLevel1');
data.addColumn({type: 'number', role: 'tooltip'});
data.addColumn({type: 'string', role: 'style'});
data.addColumn({type: 'number', role: 'annotation'});
data.addRow(['Category 1', 0 , 0, 5, 5, 5,'gray',5]);
data.addRow(['Category 2', 5 , 5, 10, 10, 10,'red',10]);
data.addRow(['Category 3', 10 , 10, 15, 15, 15,'blue',15]);
data.addRow(['Category 4', 15 , 15, 10, 10, 10,'yellow',10]);
data.addRow(['Category 5', 10 , 10, 5, 5, 5,'gray',5]);
var options = {
legend: 'none',
bar: { groupWidth: '60%' } // Remove space between bars.
};
var chart = new google.visualization.CandlestickChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
I would like to put the value of the 5th column at the top of every candlestick.
It should look like this :
Is there a way to do this?
Thanks
I add annotations to candlestick charts by adding annotations to a hidden scatter plot. You can set exactly where you want the annotations to sit by changing the plot.
google.charts.load('current', { 'packages': ['corechart'] });
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Low');
data.addColumn('number', 'Open');
data.addColumn('number', 'Close');
data.addColumn('number', 'High');
data.addColumn('number'); //scatter plot for annotations
data.addColumn({ type: 'string', role: 'annotation' }); // annotation role col.
data.addColumn({ type: 'string', role: 'annotationText' }); // annotationText col.
var high, low, open, close = 160;
for (var i = 0; i < 10; i++) {
open = close;
close += ~~(Math.random() * 10) * Math.pow(-1, ~~(Math.random() * 2));
high = Math.max(open, close) + ~~(Math.random() * 10);
low = Math.min(open, close) - ~~(Math.random() * 10);
annotation = '$' + close;
annotation_text = 'Close price: $' + close;
data.addRow([new Date(2014, 0, i + 1), low, open, close, high, high, annotation, annotation_text]);
}
var view = new google.visualization.DataView(data);
var chart = new google.visualization.ComboChart(document.querySelector('#chart_div'));
chart.draw(view, {
height: 400,
width: 600,
explorer: {},
chartArea: {
left: '7%',
width: '70%'
},
series: {
0: {
color: 'black',
type: 'candlesticks',
},
1: {
type: 'scatter',
pointSize: 0,
targetAxisIndex: 0,
},
},
candlestick: {
color: '#a52714',
fallingColor: { strokeWidth: 0, fill: '#a52714' }, // red
risingColor: { strokeWidth: 0, fill: '#0f9d58' } // green
},
});
}
<script type="text/javascript"src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div" style="width: 900px; height: 500px;"></div>
just so happens, i ran into the same problem this week
so I added my own annotations, during the 'animationfinish' event
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages:['corechart']
});
function drawChart() {
var dataChart = new google.visualization.DataTable({"cols":[{"label":"Category","type":"string"},{"label":"Bottom 1","type":"number"},{"label":"Bottom 2","type":"number"},{"label":"Top 1","type":"number"},{"label":"Top 2","type":"number"},{"role":"style","type":"string","p":{"role":"style"}}],"rows":[{"c":[{"v":"Budget"},{"v":0},{"v":0},{"v":22707893.613},{"v":22707893.613},{"v":"#007fff"}]},{"c":[{"v":"Contract Labor"},{"v":22707893.613},{"v":22707893.613},{"v":22534350.429},{"v":22534350.429},{"v":"#1e8449"}]},{"c":[{"v":"Contract Non Labor"},{"v":22534350.429},{"v":22534350.429},{"v":22930956.493},{"v":22930956.493},{"v":"#922b21"}]},{"c":[{"v":"Materials and Equipment"},{"v":22930956.493},{"v":22930956.493},{"v":22800059.612},{"v":22800059.612},{"v":"#1e8449"}]},{"c":[{"v":"Other"},{"v":22800059.612},{"v":22800059.612},{"v":21993391.103},{"v":21993391.103},{"v":"#1e8449"}]},{"c":[{"v":"Labor"},{"v":21993391.103},{"v":21993391.103},{"v":21546003.177999996},{"v":21546003.177999996},{"v":"#1e8449"}]},{"c":[{"v":"Travel"},{"v":21546003.177999996},{"v":21546003.177999996},{"v":21533258.930999994},{"v":21533258.930999994},{"v":"#1e8449"}]},{"c":[{"v":"Training"},{"v":21533258.930999994},{"v":21533258.930999994},{"v":21550964.529999994},{"v":21550964.529999994},{"v":"#922b21"}]},{"c":[{"v":"Actual"},{"v":0},{"v":0},{"v":21550964.52999999},{"v":21550964.52999999},{"v":"#007fff"}]}]});
var waterFallChart = new google.visualization.ChartWrapper({
chartType: 'CandlestickChart',
containerId: 'chart_div',
dataTable: dataChart,
options: {
animation: {
duration: 1500,
easing: 'inAndOut',
startup: true
},
backgroundColor: 'transparent',
bar: {
groupWidth: '85%'
},
chartArea: {
backgroundColor: 'transparent',
height: 210,
left: 60,
top: 24,
width: '100%'
},
hAxis: {
slantedText: false,
textStyle: {
color: '#616161',
fontSize: 9
}
},
height: 272,
legend: 'none',
tooltip: {
isHtml: true,
trigger: 'both'
},
vAxis: {
format: 'short',
gridlines: {
count: -1
},
textStyle: {
color: '#616161'
},
viewWindow: {
max: 24000000,
min: 16000000
}
},
width: '100%'
}
});
google.visualization.events.addOneTimeListener(waterFallChart, 'ready', function () {
google.visualization.events.addListener(waterFallChart.getChart(), 'animationfinish', function () {
var annotation;
var chartLayout;
var container;
var numberFormatShort;
var positionY;
var positionX;
var rowBalance;
var rowBottom;
var rowFormattedValue;
var rowIndex;
var rowTop;
var rowValue;
var rowWidth;
container = document.getElementById(waterFallChart.getContainerId());
chartLayout = waterFallChart.getChart().getChartLayoutInterface();
numberFormatShort = new google.visualization.NumberFormat({
pattern: 'short'
});
rowIndex = 0;
Array.prototype.forEach.call(container.getElementsByTagName('rect'), function(rect) {
switch (rect.getAttribute('fill')) {
// use colors to identify bars
case '#922b21':
case '#1e8449':
case '#007fff':
rowWidth = parseFloat(rect.getAttribute('width'));
if (rowWidth > 2) {
rowBottom = waterFallChart.getDataTable().getValue(rowIndex, 1);
rowTop = waterFallChart.getDataTable().getValue(rowIndex, 3);
rowValue = rowTop - rowBottom;
rowBalance = Math.max(rowBottom, rowTop);
positionY = chartLayout.getYLocation(rowBalance) - 6;
positionX = parseFloat(rect.getAttribute('x'));
rowFormattedValue = numberFormatShort.formatValue(rowValue);
if (rowValue < 0) {
rowFormattedValue = rowFormattedValue.replace('-', '');
rowFormattedValue = '(' + rowFormattedValue + ')';
}
annotation = container.getElementsByTagName('svg')[0].appendChild(container.getElementsByTagName('text')[0].cloneNode(true));
$(annotation).text(rowFormattedValue);
annotation.setAttribute('x', (positionX + (rowWidth / 2)));
annotation.setAttribute('y', positionY);
annotation.setAttribute('font-weight', 'bold');
rowIndex++;
}
break;
}
});
});
});
$(window).resize(function() {
waterFallChart.draw();
});
waterFallChart.draw();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I created a Google Timeline Chart to see my musical listening history. It looks like this:
I want to remove duration part from the tooltip, but couldn't find any option for it. I tried adding these lines:
dataTable.addColumn({type: 'string', role:'tooltip'});
and a row in my dataTable.addRows([]) function looks like this:
['25 August', 'Kasabian - La Fee Verte', new Date(2016,01,01, 13,37,32), new Date(2016,01,01, 13,43,19), 'tooltip example'],
but it still shows the same tooltip as in the image. I actually want to show Kasabian - La Fee Verte and 25 August: 1:37 pm - 1:43 pm just like in the image, but I want to remove duration.
according to the data format for a Timeline chart, the tooltip should be in the 3rd column.
see following, working snippet...
google.charts.load('current', {
callback: function () {
var container = document.getElementById('chart_div');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'RowLabel'});
dataTable.addColumn({type: 'string', id: 'BarLabel'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
dataTable.addRows([
['25 August', 'Kasabian - La Fee Verte', new Date(2016,01,01, 13,37,32), new Date(2016,01,01, 13,43,19)],
['26 August', 'Test Data 1', new Date(2016,01,01, 13,37,32), new Date(2016,01,01, 13,43,19)],
['27 August', 'Test Data 2', new Date(2016,01,01, 13,37,32), new Date(2016,01,01, 13,43,19)],
]);
dataTable.insertColumn(2, {type: 'string', role: 'tooltip', p: {html: true}});
var dateFormat = new google.visualization.DateFormat({
pattern: 'h:mm a'
});
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
var tooltip = '<div class="ggl-tooltip"><span>' +
dataTable.getValue(i, 1) + '</span></div><div class="ggl-tooltip"><span>' +
dataTable.getValue(i, 0) + '</span>: ' +
dateFormat.formatValue(dataTable.getValue(i, 3)) + ' - ' +
dateFormat.formatValue(dataTable.getValue(i, 4)) + '</div>';
dataTable.setValue(i, 2, tooltip);
}
chart.draw(dataTable, {
tooltip: {
isHtml: true
}
});
},
packages: ['timeline']
});
.ggl-tooltip {
border: 1px solid #E0E0E0;
font-family: Arial, Helvetica;
padding: 6px 6px 6px 6px;
}
.ggl-tooltip span {
font-weight: bold;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>