summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2021-01-19 12:17:22 +0100
committeremkael <emkael@tlen.pl>2021-01-19 12:17:22 +0100
commit5545d87ba4e7a59ef0e5d128d16b4bde9b716cbc (patch)
treeea30dd1d7204fdbe5e3be3ea0567c65f1f27f211
parenta90be36660d84d83b070dd0c1e95ee197ead58d1 (diff)
First version of all 4 charts
-rw-r--r--result/index.html95
-rw-r--r--result/krafcik.css73
-rw-r--r--result/krafcik.js323
3 files changed, 491 insertions, 0 deletions
diff --git a/result/index.html b/result/index.html
new file mode 100644
index 0000000..4a8009c
--- /dev/null
+++ b/result/index.html
@@ -0,0 +1,95 @@
+
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>Polski K***cik</title>
+
+ <!-- Bootstrap core CSS -->
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/css/bootstrap-slider.min.css" integrity="sha512-3q8fi8M0VS+X/3n64Ndpp6Bit7oXSiyCnzmlx6IDBLGlY5euFySyJ46RUlqIVs0DPCGOypqP8IRk/EyPvU28mQ==" crossorigin="anonymous" />
+
+ <link href="krafcik.css" rel="stylesheet" />
+
+ </head>
+ <body>
+
+ <main class="container">
+
+ <h1>Polski Krafcik <span class="lead">2012-2020</span></h1>
+
+
+ <form id="filters">
+ <div id="date-filter" class="form-group">
+ <label>Zakres dat</label>
+ <input type="text" name="date" data-slider-id="date-slider" />
+ </div>
+ <div id="brewery-filter" class="form-group">
+ <label>Browary</label><br />
+ <div class="form-check">
+ <input class="form-check-input" id="brewery-all" type="checkbox" checked="checked" />
+ <label class="form-check-label" for="brewery-all">
+ Wszystkie
+ </label>
+ </div>
+ </div>
+ </form>
+
+ <ul class="nav nav-tabs" id="tab-menu" role="tablist">
+ <li class="nav-item">
+ <a class="nav-link active" id="styles-tab" data-toggle="tab" href="#styles" role="tab" aria-controls="styles" aria-selected="true">
+ Rozkład stylów
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" id="abv-ratings-tab" data-toggle="tab" href="#abv-ratings" role="tab" aria-controls="abv-ratings" aria-selected="false">
+ ABV / l. ocen
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" id="abv-average-tab" data-toggle="tab" href="#abv-average" role="tab" aria-controls="abv-average" aria-selected="false">
+ ABV / ocena
+ </a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" id="ratings-average-tab" data-toggle="tab" href="#ratings-average" role="tab" aria-controls="ratings-average" aria-selected="false">
+ L. ocen / ocena
+ </a>
+ </li>
+ </ul>
+ <div class="tab-content" id="tab-content">
+ <div class="tab-pane fade show active" id="styles" role="tabpanel" aria-labelledby="styles-tab">
+ <canvas id="styles-chart" width="100%"></canvas>
+ </div>
+ <div class="tab-pane fade" id="abv-ratings" role="tabpanel" aria-labelledby="abv-ratings-tab">
+ <canvas id="abv-ratings-chart" width="100%"></canvas>
+ </div>
+ <div class="tab-pane fade" id="abv-average" role="tabpanel" aria-labelledby="abv-average-tab">
+ <canvas id="abv-average-chart" width="100%"></canvas>
+ </div>
+ <div class="tab-pane fade" id="ratings-average" role="tabpanel" aria-labelledby="ratings-average-tab">
+ <canvas id="ratings-average-chart" width="100%"></canvas>
+ </div>
+ </div>
+
+ </main><!-- /.container -->
+
+ <template id="brewery-template">
+ <div class="form-check form-check-inline my-2">
+ <input class="form-check-input" type="checkbox" name="brewery" checked="checked" value="" />
+ <label class="form-check-label" for="" title="">
+ <img src="" />
+ </label>
+ </div>
+ </template>
+
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
+ <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/bootstrap-slider.min.js" integrity="sha512-f0VlzJbcEB6KiW8ZVtL+5HWPDyW1+nJEjguZ5IVnSQkvZbwBt2RfCBY0CBO1PsMAqxxrG4Di6TfsCPP3ZRwKpA==" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js" integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw==" crossorigin="anonymous"></script>
+
+ <script src="krafcik.js" type="text/javascript"></script>
+
+ </body>
+</html>
diff --git a/result/krafcik.css b/result/krafcik.css
new file mode 100644
index 0000000..55a8a98
--- /dev/null
+++ b/result/krafcik.css
@@ -0,0 +1,73 @@
+html, body {
+ max-width: 100%;
+ overflow-x: hidden;
+}
+
+#date-slider {
+ width: 100%;
+}
+
+#date-filter .slider-rangeHighlight.odd {
+ background: #0000CC;
+}
+
+#date-filter .slider-rangeHighlight.even {
+ background: #8888FF;
+}
+
+#date-filter .slider-track-low,
+#date-filter .slider-track-high {
+ background: #CCCCCC;
+ z-index: 1;
+}
+
+#date-filter .slider-handle {
+ z-index: 2;
+}
+
+#brewery-filter .form-check label {
+ cursor: pointer;
+}
+
+#brewery-filter label img {
+ width: 30px;
+}
+
+#chart-tooltip {
+ position: absolute;
+ background: rgba(255, 255, 200, 0.75);
+ padding: 0.5em;
+ font-size: 0.7em;
+ border: solid 1px black;
+ pointer-events: none;
+}
+
+#chart-tooltip ul {
+ margin: 0;
+ padding: 0;
+}
+
+#chart-tooltip ul ul {
+ padding: 0 0 0 1em;
+}
+
+#chart-tooltip li {
+ list-style: none;
+}
+
+#chart-tooltip dl {
+ display: flex;
+ margin: 0;
+}
+
+#chart-tooltip dt {
+ width: 80%;
+ white-space: nowrap;
+}
+
+#chart-tooltip dd {
+ margin: 0;
+ width: 20%;
+ min-width: 30px;
+ text-align: right;
+}
diff --git a/result/krafcik.js b/result/krafcik.js
new file mode 100644
index 0000000..a65a73b
--- /dev/null
+++ b/result/krafcik.js
@@ -0,0 +1,323 @@
+$(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 = $('<div id="chart-tooltip"></div>');
+ $('body').append(container);
+ }
+ if (tooltip.body) {
+ var content = $('<ul>');
+ $.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 = $('<dt>');
+ var value = $('<dd>');
+ var item = $('<li>').append($('<dl>').append(term).append(value));
+ term.html(substyle || style);
+ value.html(count);
+ return item;
+ }
+ return null;
+ };
+ if (substyles) {
+ var sublist = $('<ul>');
+ var nonZero = false;
+ $.each(substyles, function(id, substyle) {
+ var item = getItem(style, substyle);
+ if (item) {
+ sublist.append(item);
+ nonZero = true;
+ }
+ });
+ if (nonZero) {
+ content.append($('<li>').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 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: {
+ yAxes: [{
+ type: 'logarithmic',
+ }]
+ }
+ }
+
+ });
+ }
+ });
+ 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]
+ });
+ }
+ });
+ 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: [{
+ type: 'logarithmic',
+ }]
+ }
+ }
+ });
+ }
+ });
+
+ 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')
+ })
+});