$(document).ready(function() {
$.when(
$.getJSON('beers.json'),
$.getJSON('breweries.json'),
$.getJSON('styles.json')
).done(function(beerData, breweryData, styleData) {
var beers = beerData[0];
$.each(beers, function(idx, beer) {
beer['scatter-data'] = [
{
x: beer.abv,
y: beer.ratings
},
{
x: beer.abv,
y: beer.average
},
{
x: beer.ratings,
y: beer.average
}
];
});
var minYear = Math.min.apply(null, beers.map(b => b.year));
var maxYear = Math.max.apply(null, beers.map(b => b.year));
var minMonth = Math.min.apply(null, beers.filter(b => (b.year == minYear)).map(b => b.month));
var maxMonth = Math.min.apply(null, beers.filter(b => (b.year == maxYear)).map(b => b.month));
var fullYears = maxYear - minYear - 1;
var dateCount = fullYears * 12 + (12 - minMonth + 1) + maxMonth;
var dateMapping = [];
var year = minYear;
var month = minMonth;
for (var c = 0; c < dateCount; c++) {
dateMapping[c] = year + '-' + ('0' + month).slice(-2);
month++;
if (month > 12) {
year++;
month = 1;
}
}
var valSpan = [0, dateCount-1];
var currRange = 12-minMonth+1;
var lastRange = 'odd';
var yearRanges = [{'start': 0, 'end': currRange-1, 'class': lastRange}];
while (currRange < dateCount) {
lastRange = lastRange == 'odd' ? 'even' : 'odd';
yearRanges.push({
'start': currRange,
'end': Math.min(currRange+11, dateCount-1),
'class': lastRange
});
currRange += 12;
}
$('#date-filter input[name="date"]').slider({
min: 0,
max: dateCount-1,
value: valSpan,
ticks: valSpan,
ticks_labels: valSpan.map(v => dateMapping[v]),
rangeHighlights: yearRanges,
formatter: function(val) {
if (isNaN(val)) {
return val.map(v => dateMapping[v]).join(' - ');
}
else {
return dateMapping[val];
}
}
});
var breweries = breweryData[0];
var breweryTemplate = $('#brewery-template').html();
var breweryFilter = $('#brewery-filter');
$.each(breweries, function(brewery, data) {
var fieldId = 'brewery-' + brewery;
var field = $(breweryTemplate);
field.find('input').attr('value', brewery).attr('id', fieldId);
field.find('label').attr('for', fieldId).attr('title', data['name']).find('img').attr('src', 'img/' + data['logo']);
breweryFilter.append(field);
field.find('label').tooltip();
});
$('#brewery-all').change(function() {
if ($(this).is(':checked')) {
$('#brewery-filter .form-check input').prop('checked', 'checked');
} else {
$('#brewery-filter .form-check input').prop('checked', null);
}
});
var styles = styleData[0];
$.each(styles, function(idx, style) {
style.styleTree = {};
$.each(style.styles.map(s => s.split(' - ')), function(idx, splitStyle) {
if (splitStyle.length > 1) {
if (!style.styleTree[splitStyle[0]]) {
style.styleTree[splitStyle[0]] = [];
}
style.styleTree[splitStyle[0]].push(splitStyle[1]);
} else {
style.styleTree[splitStyle[0]] = null;
}
});
});
var styleNames = styles.map(s => s.name);
var styleCounts = styles.map(s => 0);
var substyleCounts = [];
var styleSubstyles = styles.map(s => s.styles);
var styleColours = styles.map(s => s.colour);
var scatterChartData = [];
for (var i = 0; i < 3; i++) {
scatterChartData[i] = {
datasets: styles.map(function(style) {
return {
borderColor: style.colour,
backgroundColor: Color(style.colour).alpha(0.5).rgbString(),
data: []
};
})
};
}
var stylesChart;
$('a#styles-tab').on('shown.bs.tab', function() {
if (!stylesChart) {
var ctx = $('#styles-chart')[0].getContext('2d');
stylesChart = new Chart(ctx, {
type: 'bar',
data: {
labels: styleNames,
datasets: [{
data: styleCounts,
backgroundColor: styleColours,
borderColor: '#000000',
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
tooltips: {
enabled: false,
custom: function(tooltip) {
var container = $('#chart-tooltip');
if (!container.length) {
container = $('
');
$('body').append(container);
}
if (tooltip.body) {
var content = $('');
$.each(styles[tooltip.dataPoints[0].index].styleTree, function(style, substyles) {
var getItem = function(style, substyle) {
var count = substyleCounts[substyle ? (style + ' - ' + substyle) : style];
if (count) {
var term = $('- ');
var value = $('
- ');
var item = $('
- ').append($('
').append(term).append(value));
term.html(substyle || style);
value.html(count);
return item;
}
return null;
};
if (substyles) {
var sublist = $('');
var nonZero = false;
$.each(substyles, function(id, substyle) {
var item = getItem(style, substyle);
if (item) {
sublist.append(item);
nonZero = true;
}
});
if (nonZero) {
content.append($('- ').append(style).append(sublist));
}
} else {
content.append(getItem(style));
}
});
var positionY = this._chart.canvas.offsetTop;
var positionX = this._chart.canvas.offsetLeft;
container.html(content).show();
container.css({
'top': Math.min(
positionY + tooltip.caretY,
$('body').height() - container.outerHeight()
),
'left': Math.min(
positionX + tooltip.caretX,
$('body').width() - container.outerWidth()
)
}).show();
} else {
container.html('').hide();
}
}
}
}
});
}
});
var ratingAxis = {
type: 'logarithmic',
ticks: {
min: 15,
max: Math.ceil(Math.max.apply(null, beers.map(b => b.ratings)) / 1000) * 1000,
callback: value => value.toLocaleString()
}
};
var averageAxis = {
ticks: {
min: Math.floor(Math.min.apply(null, beers.map(b => b.average)) * 2) * 0.5,
max: 5
}
};
var abvAxis = {
ticks: {
beginAtZero: true,
min: 0,
max: Math.ceil(Math.max.apply(null, beers.map(b => b.abv)) * 2) * 0.5
}
};
var abvRatingsChart;
$('a#abv-ratings-tab').on('shown.bs.tab', function() {
if (!abvRatingsChart) {
var ctx = $('#abv-ratings-chart')[0].getContext('2d');
abvRatingsChart = new Chart.Scatter(ctx, {
data: scatterChartData[0],
options: {
scales: {
xAxes: [abvAxis],
yAxes: [ratingAxis]
}
}
});
}
});
var abvAverageChart;
$('a#abv-average-tab').on('shown.bs.tab', function() {
if (!abvAverageChart) {
var ctx = $('#abv-average-chart')[0].getContext('2d');
abvAverageChart = new Chart.Scatter(ctx, {
data: scatterChartData[1],
options: {
scales: {
xAxis: [abvAxis],
yAxes: [averageAxis]
}
}
});
}
});
var ratingsAverageChart;
$('a#ratings-average-tab').on('shown.bs.tab', function() {
if (!ratingsAverageChart) {
var ctx = $('#ratings-average-chart')[0].getContext('2d');
ratingsAverageChart = new Chart.Scatter(ctx, {
data: scatterChartData[2],
options: {
scales: {
xAxes: [ratingAxis],
yAxes: [averageAxis]
}
}
});
}
});
var getFilteredBeers = function(beers) {
var dates = $('#date-filter input[name="date"]').val().split(',').map(d => dateMapping[parseInt(d)]);
var breweries = $('#brewery-filter input:checked').map(function(i, input) { return input.value; }).toArray();
return beers.filter(function(beer) {
var added = beer.year + '-' + ('0' + beer.month).slice(-2);
return (breweries.indexOf(beer.brewery) > -1)
&& (added >= dates[0] && added <= dates[1]);
});
};
var updateCharts = function() {
var filtered = getFilteredBeers(beers);
var bySubstyle = {};
for (var style in substyleCounts) {
substyleCounts[style] = 0;
}
for (var beer in filtered) {
var style = filtered[beer].style.join(' - ');
if (!substyleCounts[style]) {
substyleCounts[style] = 0;
}
substyleCounts[style]++;
if (!bySubstyle[style]) {
bySubstyle[style] = [];
}
bySubstyle[style].push(filtered[beer]['scatter-data']);
}
for (var s in styleCounts) {
styleCounts[s] = 0;
for (var i = 0; i < 3; i++) {
scatterChartData[i].datasets[s].data = [];
}
for (var ss in styleSubstyles[s]) {
var substyle = styleSubstyles[s][ss];
if (substyleCounts[substyle]) {
styleCounts[s] += substyleCounts[substyle];
for (var i = 0; i < 3; i++) {
scatterChartData[i].datasets[s].data = scatterChartData[i].datasets[s].data.concat(bySubstyle[substyle].map(d => d[i]));
}
}
}
}
if (stylesChart) {
stylesChart.update();
}
if (abvRatingsChart) {
abvRatingsChart.update();
}
if (abvAverageChart) {
abvAverageChart.update();
}
if (ratingsAverageChart) {
ratingsAverageChart.update();
}
};
var changeTimeout = null;
$('#date-filter, #brewery-filter').find('input').change(function() {
clearTimeout(changeTimeout);
changeTimeout = setTimeout(updateCharts, 500);
});
$('a#styles-tab').trigger('shown.bs.tab');
updateCharts();
});
$('#tab-menu a').on('click', function (e) {
e.preventDefault()
$(this).tab('show')
})
});