$(document).ready(function() {
var initTab = function(tab, push) {
if (!tab) {
tab = location.hash.replace('#', '') || 'styles';
}
$(`a#${tab}-tab`).tab('show');
if (push) {
history.pushState({}, '', '#' + tab);
}
};
$.when(
$.getJSON('beers.json'),
$.getJSON('breweries.json'),
$.getJSON('styles.json')
).done(function(beerData, breweryData, styleData) {
var compileDate = Date.parse($('time#compile-date').attr('datetime'));
var beers = beerData[0];
$.each(beers, function(idx, beer) {
var addedDate = new Date();
addedDate.setYear(beer.added.year);
addedDate.setMonth(beer.added.month-1);
addedDate.setDate(beer.added.day);
var dateDiff = Math.ceil((compileDate - addedDate.getTime()) / (1000 * 60 * 60 * 24 * 30));
if (!beer.in_production) {
dateDiff = Math.min(dateDiff, 12);
}
beer.ratings.adjusted = beer.ratings.count / dateDiff;
beer['scatter-data'] = [
{
x: beer.abv,
y: beer.ratings.adjusted,
ref: beer
},
{
x: beer.abv,
y: beer.ratings.average,
ref: beer
},
{
x: beer.ratings.adjusted,
y: beer.ratings.average,
ref: beer
}
];
});
var minYear = Math.min.apply(null, beers.map(b => b.added.year));
var maxYear = Math.max.apply(null, beers.map(b => b.added.year));
var minMonth = Math.min.apply(null, beers.filter(b => (b.added.year == minYear)).map(b => b.added.month));
var maxMonth = Math.max.apply(null, beers.filter(b => (b.added.year == maxYear)).map(b => b.added.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(),
label: style.name,
data: []
};
})
};
}
var displayTooltip = function(chart, tooltip, data, contentFunction) {
var container = $('#chart-tooltip');
if (!container.length) {
container = $('
');
}
$(chart.canvas).parent().append(container);
if (tooltip.body) {
var positionY = chart.canvas.offsetTop;
var positionX = chart.canvas.offsetLeft;
container.html(contentFunction(tooltip, data)).show();
container.css({
'top': Math.min(
positionY + tooltip.caretY,
$('body').height() - container.outerHeight()
),
'left': Math.min(
positionX + tooltip.caretX,
$('body').width() - container.outerWidth()
)
}).addClass(chart.canvas.id).show();
} else {
container.html('').removeAttr('class').hide();
}
};
var scatterTooltip = function(tooltip, data) {
var content = $('');
var datasets = data.datasets;
$.each(tooltip.dataPoints, function(d, dataPoint) {
var beer = datasets[dataPoint.datasetIndex].data[dataPoint.index].ref;
content.append(
$('
').append($('
').text(beer.name)),
$('').append($('
').text(breweries[beer.brewery].name)),
$('').append($('
').text(beer.style.join(' - '))),
$('').append(
$('- ').text('ABV'),
$('
- ').text(`${beer.abv}%`),
$('
- ').text('L. ocen'),
$('
- ').text(beer.ratings.count),
$('
- ').text('Śr. ocen'),
$('
- ').text(beer.ratings.average),
$('
- ').text('Dodane'),
$('
- ').text([
`0${beer.added.day}`.slice(-2),
`0${beer.added.month}`.slice(-2),
beer.added.year
].join('-'))
)
);
});
return content;
};
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.map(c => Color(c).alpha(0.5).rgbString()),
borderColor: styleColours,
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
tooltips: {
enabled: false,
custom: function(tooltip) {
displayTooltip(this._chart, tooltip, this._data, function(tooltip, data) {
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, 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, sublist));
}
} else {
content.append(getItem(style));
}
});
return content;
});
}
}
}
});
}
});
var ratingAxis = {
type: 'logarithmic',
ticks: {
min: 0,
callback: value => value.toLocaleString(),
autoSkipPadding: 20
}
};
var averageAxis = {
ticks: {
min: Math.floor(Math.min.apply(null, beers.map(b => b.ratings.average)) * 2) * 0.5,
max: 5
}
};
var abvAxis = {
ticks: {
min: 0
}
};
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: {
maintainAspectRatio: false,
scales: {
xAxes: [abvAxis],
yAxes: [ratingAxis]
},
tooltips: {
enabled: false,
custom: function(tooltip) {
displayTooltip(this._chart, tooltip, this._data, scatterTooltip);
}
}
}
});
}
});
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: {
maintainAspectRatio: false,
scales: {
xAxis: [abvAxis],
yAxes: [averageAxis]
},
tooltips: {
enabled: false,
custom: function(tooltip) {
displayTooltip(this._chart, tooltip, this._data, scatterTooltip);
}
}
}
});
}
});
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: {
maintainAspectRatio: false,
scales: {
xAxes: [ratingAxis],
yAxes: [averageAxis]
},
tooltips: {
enabled: false,
custom: function(tooltip) {
displayTooltip(this._chart, tooltip, this._data, scatterTooltip);
}
}
}
});
}
});
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.added.year + '-' + `0${beer.added.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 s in substyleCounts) {
substyleCounts[s] = 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 j = 0; j < 3; j++) {
scatterChartData[j].datasets[s].data = scatterChartData[j].datasets[s].data.concat(bySubstyle[substyle].map(d => d[j]));
}
}
}
}
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);
});
initTab(false, true);
updateCharts();
});
$('#tab-menu a').on('click', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
initTab($(this).attr('aria-controls'), true);
return false;
});
$(window).on('popstate', function(ev) {
initTab(false, false);
});
});