Annotation Chart Example
An example of a Google Annotation Chart.
by JakobJingleheimer
HTML
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div class="chart-container">
<figure
class="chart"
data-title="testing…"
>
<table class="chart-data">
<thead>
<tr>
<th data-type="date">Period</th>
<th data-type="number">Allocations</th>
<th
data-role="tooltip"
data-type="string"
>Note</th>
</tr>
</thead>
<tbody>
<tr>
<td data-type="date">Jan 2014</td>
<td data-type="number">200</td>
</tr>
<tr>
<td data-type="date">Jul 2014</td>
<td data-type="number">231</td>
</tr>
<tr>
<td data-type="date">Jan 2015</td>
<td data-type="number">368</td>
</tr>
<tr>
<td data-type="date">Jul 2015</td>
<td data-type="number">218</td>
</tr>
<tr>
<td data-type="date">Jan 2016</td>
<td data-type="number">9</td>
</tr>
<tr>
<td data-type="date">Jul 2016</td>
<td data-emphasis="true" data-type="number">8964</td>
<td data-type="string">Free money</td>
</tr>
<tr>
<td data-type="date">Jan 2017</td>
<td data-type="number">168</td>
</tr>
</tbody>
</table>
</figure>
<caption></caption>
</div>
SCSS
html {
font-family: Arial;
font-size: 14px;
}
html,
body {
display: block;
height: 100%;
width: 100%;
}
.chart-container {
padding-top: 100%;
position: relative;
width: 100%;
}
.chart {
height: 100%;
margin: 0;
position: absolute;
top: 0;
width: 100%;
}
.chart-data {
[data-type="date"],
[data-type="number"] {
text-align: right;
}
th {
font-weight: bold;
}
th,
td {
padding: 0.4em;
}
}
JavaScript
let AnnotationChart;
const drawChart = (elm) => {
if (!elm) return false;
const sourceData = readData(elm);
const data = new google.visualization.DataTable();
sourceData.columns.forEach((col) => {
data.addColumn(col);
});
data.addRows(sourceData.rows);
const chart = new AnnotationChart(elm);
const options = Object.assign(
{
displayAnnotations: true,
interpolateNulls: true,
},
elm.dataset
);
return chart.draw(data, options);
};
const formats = {
date: (val) => {
const v = new Date(val);
const f = new Intl
.DateTimeFormat(
'en-UK',
{
month: 'short',
year: 'numeric',
}
)
.format(v);
return {
f,
v
};
},
number: (val) => {
return {
v: JSON.parse(val)
};
}
};
const reduceTds = (r, td, i) => {
const formatter = formats[td.dataset.type];
const v = td.textContent;
if (formatter) r[i] = formatter(v);
else r[i] = { v };
return r;
};
const reduceThs = (r, th, i) => {
r[i] = Object.assign(
{},
{
label: th.textContent,
},
th.dataset
);
return r;
};
const readData = (elm) => {
const table = elm.getElementsByClassName('chart-data')[0];
const columns = Array
.from(table.getElementsByTagName('th'))
.reduce(
reduceThs,
[]
);
const reduceDataRows = (r, tr, i) => {
const row = Array
.from(tr.getElementsByTagName('td'))
.reduce(
reduceTds,
[]
);
let sizeDiff = columns.length - row.length;
while (sizeDiff--) {
row.push(null);
}
r[i] = row;
return r;
};
const rows = Array
.from(table.getElementsByTagName('tbody')[0].getElementsByTagName('tr'))
.reduce(
reduceDataRows,
[]
);
return {
columns,
rows,
};
};
const onLoad = () => {
AnnotationChart = google.visualization.LineChart;
const charts = Array.from(document.getElementsByClassName('chart'));
charts.forEach(drawChart);
};
google.charts.load('current', { 'packages': ['corechart'] });
google.charts.setOnLoadCallback(onLoad);