Added mining inflation chart to stats page #34
5 changed files with 524 additions and 237 deletions
|
@ -134,236 +134,7 @@
|
||||||
<script type="text/javascript" src="/amcharts/amcharts.js"></script>
|
<script type="text/javascript" src="/amcharts/amcharts.js"></script>
|
||||||
<script type="text/javascript" src="/amcharts/serial.js"></script>
|
<script type="text/javascript" src="/amcharts/serial.js"></script>
|
||||||
<script type="text/javascript" src="/amcharts/plugins/export/export.min.js"></script>
|
<script type="text/javascript" src="/amcharts/plugins/export/export.min.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript" src="/js/block-size-chart.js"></script>
|
||||||
var chart;
|
|
||||||
var chartData = [];
|
|
||||||
var chartLoadInProgress = false;
|
|
||||||
var minPeriod = 'hh';
|
|
||||||
var validPeriods = ['24h', '72h', '168h', '30d', '90d', '1y'];
|
|
||||||
var defaultPeriod = (validPeriods.indexOf(localStorage.getItem('chartPeriod')) > -1) ? localStorage.getItem('chartPeriod') : '24h';
|
|
||||||
var periodGridCounts = {'24h': 24, '72h': 24, '168h': 14, '30d': 30, '90d': 45, '1y': 12 };
|
|
||||||
AmCharts.ready(function() {
|
|
||||||
chart = AmCharts.makeChart('block-size-chart', {
|
|
||||||
type: 'serial',
|
|
||||||
theme: 'light',
|
|
||||||
mouseWheelZoomEnabled: true,
|
|
||||||
categoryField: 'date',
|
|
||||||
synchronizeGrid: true,
|
|
||||||
dataProvider: chartData,
|
|
||||||
valueAxes: [
|
|
||||||
{
|
|
||||||
id: 'v-block-size',
|
|
||||||
axisColor: '#1e88e5',
|
|
||||||
axisThickness: 2,
|
|
||||||
labelFunction: function(value) {
|
|
||||||
return (Math.round((value / 1000) * 100)/100).toFixed(2) + ' KB';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'v-price',
|
|
||||||
axisColor: '#00e676',
|
|
||||||
offset: 75,
|
|
||||||
gridAlpha: 0,
|
|
||||||
axisThickness: 2,
|
|
||||||
labelFunction: function(value) {
|
|
||||||
return '$' + value.toFixed(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
categoryAxis: {
|
|
||||||
parseDates: true,
|
|
||||||
minPeriod: minPeriod, // DD for daily
|
|
||||||
autoGridCount: false,
|
|
||||||
minorGridEnabled: true,
|
|
||||||
minorGridAlpha: 0.04,
|
|
||||||
axisColor: '#dadada',
|
|
||||||
twoLineMode: true,
|
|
||||||
dateFormats: [{
|
|
||||||
period: 'fff',
|
|
||||||
format: 'JJ:NN:SS'
|
|
||||||
}, {
|
|
||||||
period: 'ss',
|
|
||||||
format: 'JJ:NN:SS'
|
|
||||||
}, {
|
|
||||||
period: 'mm',
|
|
||||||
format: 'JJ:NN'
|
|
||||||
}, {
|
|
||||||
period: 'hh',
|
|
||||||
format: 'JJ:NN'
|
|
||||||
}, {
|
|
||||||
period: 'DD',
|
|
||||||
format: 'DD'
|
|
||||||
}, {
|
|
||||||
period: 'WW',
|
|
||||||
format: 'DD MMM'
|
|
||||||
}, {
|
|
||||||
period: 'MM',
|
|
||||||
format: 'MMM'
|
|
||||||
}, {
|
|
||||||
period: 'YYYY',
|
|
||||||
format: 'YYYY'
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
graphs: [
|
|
||||||
{
|
|
||||||
id: 'g-block-size',
|
|
||||||
valueAxis: 'v-block-size', // we have to indicate which value axis should be used
|
|
||||||
title: 'Avg Block Size',
|
|
||||||
valueField: 'AvgBlockSize',
|
|
||||||
bullet: 'round',
|
|
||||||
bulletBorderThickness: 1,
|
|
||||||
bulletBorderAlpha: 1,
|
|
||||||
bulletColor: '#ffffff',
|
|
||||||
bulletSize: 5,
|
|
||||||
useLineColorForBulletBorder: true,
|
|
||||||
lineColor: '#1e88e5',
|
|
||||||
hideBulletsCount: 101,
|
|
||||||
balloonText: '[[AvgBlockSize]] KB',
|
|
||||||
switchable: false,
|
|
||||||
balloonFunction: function(item, graph) {
|
|
||||||
var result = graph.balloonText;
|
|
||||||
return result.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'g-price',
|
|
||||||
valueAxis: 'v-price',
|
|
||||||
title: 'Average Price',
|
|
||||||
valueField: 'AvgUSD',
|
|
||||||
bullet: 'round',
|
|
||||||
bulletBorderThickness: 1,
|
|
||||||
bulletBorderAlpha: 1,
|
|
||||||
bulletColor: '#ffffff',
|
|
||||||
bulletSize: 5,
|
|
||||||
useLineColorForBulletBorder: true,
|
|
||||||
lineColor: '#00e676',
|
|
||||||
balloonText: '$[[AvgUSD]]',
|
|
||||||
balloonFunction: function(item, graph) {
|
|
||||||
var result = graph.balloonText;
|
|
||||||
if (!item.dataContext.AvgUSD) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return result.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
|
|
||||||
},
|
|
||||||
hideBulletsCount: 101,
|
|
||||||
labelFunction: function(value) {
|
|
||||||
return '$' + value;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
chartCursor: {
|
|
||||||
cursorAlpha: 0.1,
|
|
||||||
fullWidth: true,
|
|
||||||
valueLineBalloonEnabled: true,
|
|
||||||
categoryBalloonColor: '#333333',
|
|
||||||
cursorColor: '#1e88e5',
|
|
||||||
categoryBalloonDateFormat: minPeriod === 'hh' ? 'D MMM HH:NN ' : 'D MMM'
|
|
||||||
},
|
|
||||||
chartScrollbar: {
|
|
||||||
scrollbarHeight: 36,
|
|
||||||
color: '#888888',
|
|
||||||
gridColor: '#bbbbbb'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
marginLeft: 110,
|
|
||||||
useGraphSettings: true,
|
|
||||||
valueAlign: 'right',
|
|
||||||
valueWidth: 60,
|
|
||||||
spacing: 64,
|
|
||||||
valueFunction: function(item, formatted) {
|
|
||||||
if (item.dataContext) {
|
|
||||||
var g = item.graph;
|
|
||||||
if (g.id === 'g-block-size' && item.dataContext.AvgBlockSize > 0) {
|
|
||||||
return g.balloonText.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2) );
|
|
||||||
}
|
|
||||||
if (g.id === 'g-price' && item.dataContext.AvgUSD) {
|
|
||||||
return g.balloonText.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatted;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
export: {
|
|
||||||
enabled: true,
|
|
||||||
fileName: 'lbry-block-size-chart',
|
|
||||||
position: 'bottom-right',
|
|
||||||
divId: 'chart-export'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
loadChartData(defaultPeriod);
|
|
||||||
});
|
|
||||||
|
|
||||||
var loadChartData = function(dataPeriod) {
|
|
||||||
var loadProgress = $('.block-size-chart-container .load-progress');
|
|
||||||
// clear previous chart data
|
|
||||||
$.ajax({
|
|
||||||
url: '/api/v1/charts/blocksize/' + dataPeriod,
|
|
||||||
type: 'get',
|
|
||||||
dataType: 'json',
|
|
||||||
beforeSend: function() {
|
|
||||||
chartLoadInProgress = true;
|
|
||||||
loadProgress.css({ display: 'block' });
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
if (response.success) {
|
|
||||||
chartData = [];
|
|
||||||
var data = response.data;
|
|
||||||
for (var period in data) {
|
|
||||||
if (data.hasOwnProperty(period)) {
|
|
||||||
chartData.push({
|
|
||||||
date: Date.parse(period),
|
|
||||||
AvgBlockSize: data[period].AvgBlockSize,
|
|
||||||
AvgUSD: data[period].AvgUSD
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// save selcted period to localStorage
|
|
||||||
localStorage.setItem('chartPeriod', dataPeriod);
|
|
||||||
|
|
||||||
if (chart) {
|
|
||||||
var isHourly = (dataPeriod.indexOf('h') > -1);
|
|
||||||
var gridCount = periodGridCounts[dataPeriod];
|
|
||||||
chart.categoryAxis.minPeriod = isHourly ? 'hh' : 'DD';
|
|
||||||
chart.categoryAxis.dateFormats[4].format = isHourly ? 'DD MMM' : 'DD';
|
|
||||||
chart.chartCursor.categoryBalloonDateFormat = isHourly ? 'D MMM HH:NN ' : 'D MMM YYYY';
|
|
||||||
chart.categoryAxis.gridCount = gridCount;
|
|
||||||
chart.chartScrollbar.gridCount = gridCount;
|
|
||||||
chart.dataProvider = chartData;
|
|
||||||
chart.validateNow();
|
|
||||||
chart.validateData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function() {
|
|
||||||
chartLoadInProgress = false;
|
|
||||||
loadProgress.css({ display: 'none' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('.block-size-data-links a').on('click', function(evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
if (chartLoadInProgress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var link = $(this);
|
|
||||||
if (link.hasClass('active')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
link.addClass('active').siblings().removeClass('active');
|
|
||||||
var period = link.attr('data-period');
|
|
||||||
loadChartData(period);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('a[data-period="' + defaultPeriod + '"]').addClass('active').siblings().removeClass('active');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<?php $this->end(); ?>
|
<?php $this->end(); ?>
|
||||||
|
|
||||||
<div class="block-head">
|
<div class="block-head">
|
||||||
|
|
|
@ -1,19 +1,34 @@
|
||||||
<?php $this->assign('title', 'Stats & Rich List') ?>
|
<?php $this->assign('title', 'Stats & Rich List') ?>
|
||||||
|
|
||||||
<?php $this->start('script'); ?>
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<?php $this->end(); ?>
|
|
||||||
|
|
||||||
<?php echo $this->element('header') ?>
|
<?php echo $this->element('header') ?>
|
||||||
|
|
||||||
|
<?php $this->start('script'); ?>
|
||||||
|
<script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
|
||||||
|
<script src="https://www.amcharts.com/lib/3/serial.js"></script>
|
||||||
|
<script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
|
||||||
|
<script src="https://www.amcharts.com/lib/3/plugins/responsive/responsive.min.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript" src="/js/mining-inflation-chart.js"></script>
|
||||||
|
<?php $this->end(); ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$this->start('css');
|
||||||
|
echo $this->Html->css('/css/mining-inflation-chart.css');
|
||||||
|
echo $this->Html->css('https://www.amcharts.com/lib/3/plugins/export/export.css');
|
||||||
|
$this->end();
|
||||||
|
?>
|
||||||
<div class="stats-head">
|
<div class="stats-head">
|
||||||
<h3>LBRY Stats</h3>
|
<h3>LBRY Stats</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stats-main">
|
<div class="stats-main">
|
||||||
|
|
||||||
|
<div class="mining-inflation-chart-container">
|
||||||
|
<div class="load-progress inc"></div>
|
||||||
|
<h3>Mining Inflation Chart</h3>
|
||||||
|
<div id="mining-inflation-chart" class="chart"></div>
|
||||||
|
<div id="chart-export" class="btn-chart-export"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="richlist">
|
<div class="richlist">
|
||||||
<h3>LBRY Rich List (Top 500)</h3>
|
<h3>LBRY Rich List (Top 500)</h3>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
|
8
webroot/css/mining-inflation-chart.css
Normal file
8
webroot/css/mining-inflation-chart.css
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.mining-inflation-chart-container { width: 1200px; margin: 0 auto 48px auto; box-shadow: 0 2px 6px rgba(0,0,0,.175); border: 1px solid rgba(0,0,0,.15); padding: 24px 36px; position: relative; overflow: hidden }
|
||||||
|
.mining-inflation-chart-container .load-progress { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: #1e88e5; animation: indeterminate 4s linear infinite; }
|
||||||
|
.mining-inflation-chart-container .chart { height: 414px }
|
||||||
|
.mining-inflation-chart-container .btn-chart-export { position: absolute; right: 40px; bottom: 36px }
|
||||||
|
@keyframes indeterminate {
|
||||||
|
from { left: -70%; }
|
||||||
|
to { left: 100% }
|
||||||
|
}
|
228
webroot/js/block-size-chart.js
Normal file
228
webroot/js/block-size-chart.js
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
var chart;
|
||||||
|
var chartData = [];
|
||||||
|
var chartLoadInProgress = false;
|
||||||
|
var minPeriod = 'hh';
|
||||||
|
var validPeriods = ['24h', '72h', '168h', '30d', '90d', '1y'];
|
||||||
|
var defaultPeriod = (validPeriods.indexOf(localStorage.getItem('chartPeriod')) > -1) ? localStorage.getItem('chartPeriod') : '24h';
|
||||||
|
var periodGridCounts = {'24h': 24, '72h': 24, '168h': 14, '30d': 30, '90d': 45, '1y': 12 };
|
||||||
|
AmCharts.ready(function() {
|
||||||
|
chart = AmCharts.makeChart('block-size-chart', {
|
||||||
|
type: 'serial',
|
||||||
|
theme: 'light',
|
||||||
|
mouseWheelZoomEnabled: true,
|
||||||
|
categoryField: 'date',
|
||||||
|
synchronizeGrid: true,
|
||||||
|
dataProvider: chartData,
|
||||||
|
valueAxes: [
|
||||||
|
{
|
||||||
|
id: 'v-block-size',
|
||||||
|
axisColor: '#1e88e5',
|
||||||
|
axisThickness: 2,
|
||||||
|
labelFunction: function(value) {
|
||||||
|
return (Math.round((value / 1000) * 100)/100).toFixed(2) + ' KB';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v-price',
|
||||||
|
axisColor: '#00e676',
|
||||||
|
offset: 75,
|
||||||
|
gridAlpha: 0,
|
||||||
|
axisThickness: 2,
|
||||||
|
labelFunction: function(value) {
|
||||||
|
return '$' + value.toFixed(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
categoryAxis: {
|
||||||
|
parseDates: true,
|
||||||
|
minPeriod: minPeriod, // DD for daily
|
||||||
|
autoGridCount: false,
|
||||||
|
minorGridEnabled: true,
|
||||||
|
minorGridAlpha: 0.04,
|
||||||
|
axisColor: '#dadada',
|
||||||
|
twoLineMode: true,
|
||||||
|
dateFormats: [{
|
||||||
|
period: 'fff',
|
||||||
|
format: 'JJ:NN:SS'
|
||||||
|
}, {
|
||||||
|
period: 'ss',
|
||||||
|
format: 'JJ:NN:SS'
|
||||||
|
}, {
|
||||||
|
period: 'mm',
|
||||||
|
format: 'JJ:NN'
|
||||||
|
}, {
|
||||||
|
period: 'hh',
|
||||||
|
format: 'JJ:NN'
|
||||||
|
}, {
|
||||||
|
period: 'DD',
|
||||||
|
format: 'DD'
|
||||||
|
}, {
|
||||||
|
period: 'WW',
|
||||||
|
format: 'DD MMM'
|
||||||
|
}, {
|
||||||
|
period: 'MM',
|
||||||
|
format: 'MMM'
|
||||||
|
}, {
|
||||||
|
period: 'YYYY',
|
||||||
|
format: 'YYYY'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
graphs: [
|
||||||
|
{
|
||||||
|
id: 'g-block-size',
|
||||||
|
valueAxis: 'v-block-size', // we have to indicate which value axis should be used
|
||||||
|
title: 'Avg Block Size',
|
||||||
|
valueField: 'AvgBlockSize',
|
||||||
|
bullet: 'round',
|
||||||
|
bulletBorderThickness: 1,
|
||||||
|
bulletBorderAlpha: 1,
|
||||||
|
bulletColor: '#ffffff',
|
||||||
|
bulletSize: 5,
|
||||||
|
useLineColorForBulletBorder: true,
|
||||||
|
lineColor: '#1e88e5',
|
||||||
|
hideBulletsCount: 101,
|
||||||
|
balloonText: '[[AvgBlockSize]] KB',
|
||||||
|
switchable: false,
|
||||||
|
balloonFunction: function(item, graph) {
|
||||||
|
var result = graph.balloonText;
|
||||||
|
return result.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'g-price',
|
||||||
|
valueAxis: 'v-price',
|
||||||
|
title: 'Average Price',
|
||||||
|
valueField: 'AvgUSD',
|
||||||
|
bullet: 'round',
|
||||||
|
bulletBorderThickness: 1,
|
||||||
|
bulletBorderAlpha: 1,
|
||||||
|
bulletColor: '#ffffff',
|
||||||
|
bulletSize: 5,
|
||||||
|
useLineColorForBulletBorder: true,
|
||||||
|
lineColor: '#00e676',
|
||||||
|
balloonText: '$[[AvgUSD]]',
|
||||||
|
balloonFunction: function(item, graph) {
|
||||||
|
var result = graph.balloonText;
|
||||||
|
if (!item.dataContext.AvgUSD) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return result.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
|
||||||
|
},
|
||||||
|
hideBulletsCount: 101,
|
||||||
|
labelFunction: function(value) {
|
||||||
|
return '$' + value;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
chartCursor: {
|
||||||
|
cursorAlpha: 0.1,
|
||||||
|
fullWidth: true,
|
||||||
|
valueLineBalloonEnabled: true,
|
||||||
|
categoryBalloonColor: '#333333',
|
||||||
|
cursorColor: '#1e88e5',
|
||||||
|
categoryBalloonDateFormat: minPeriod === 'hh' ? 'D MMM HH:NN ' : 'D MMM'
|
||||||
|
},
|
||||||
|
chartScrollbar: {
|
||||||
|
scrollbarHeight: 36,
|
||||||
|
color: '#888888',
|
||||||
|
gridColor: '#bbbbbb'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
marginLeft: 110,
|
||||||
|
useGraphSettings: true,
|
||||||
|
valueAlign: 'right',
|
||||||
|
valueWidth: 60,
|
||||||
|
spacing: 64,
|
||||||
|
valueFunction: function(item, formatted) {
|
||||||
|
if (item.dataContext) {
|
||||||
|
var g = item.graph;
|
||||||
|
if (g.id === 'g-block-size' && item.dataContext.AvgBlockSize > 0) {
|
||||||
|
return g.balloonText.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2) );
|
||||||
|
}
|
||||||
|
if (g.id === 'g-price' && item.dataContext.AvgUSD) {
|
||||||
|
return g.balloonText.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
export: {
|
||||||
|
enabled: true,
|
||||||
|
fileName: 'lbry-block-size-chart',
|
||||||
|
position: 'bottom-right',
|
||||||
|
divId: 'chart-export'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadChartData(defaultPeriod);
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadChartData = function(dataPeriod) {
|
||||||
|
var loadProgress = $('.block-size-chart-container .load-progress');
|
||||||
|
// clear previous chart data
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/v1/charts/blocksize/' + dataPeriod,
|
||||||
|
type: 'get',
|
||||||
|
dataType: 'json',
|
||||||
|
beforeSend: function() {
|
||||||
|
chartLoadInProgress = true;
|
||||||
|
loadProgress.css({ display: 'block' });
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
chartData = [];
|
||||||
|
var data = response.data;
|
||||||
|
for (var period in data) {
|
||||||
|
if (data.hasOwnProperty(period)) {
|
||||||
|
chartData.push({
|
||||||
|
date: Date.parse(period),
|
||||||
|
AvgBlockSize: data[period].AvgBlockSize,
|
||||||
|
AvgUSD: data[period].AvgUSD
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save selcted period to localStorage
|
||||||
|
localStorage.setItem('chartPeriod', dataPeriod);
|
||||||
|
|
||||||
|
if (chart) {
|
||||||
|
var isHourly = (dataPeriod.indexOf('h') > -1);
|
||||||
|
var gridCount = periodGridCounts[dataPeriod];
|
||||||
|
chart.categoryAxis.minPeriod = isHourly ? 'hh' : 'DD';
|
||||||
|
chart.categoryAxis.dateFormats[4].format = isHourly ? 'DD MMM' : 'DD';
|
||||||
|
chart.chartCursor.categoryBalloonDateFormat = isHourly ? 'D MMM HH:NN ' : 'D MMM YYYY';
|
||||||
|
chart.categoryAxis.gridCount = gridCount;
|
||||||
|
chart.chartScrollbar.gridCount = gridCount;
|
||||||
|
chart.dataProvider = chartData;
|
||||||
|
chart.validateNow();
|
||||||
|
chart.validateData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
chartLoadInProgress = false;
|
||||||
|
loadProgress.css({ display: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.block-size-data-links a').on('click', function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (chartLoadInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var link = $(this);
|
||||||
|
if (link.hasClass('active')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
link.addClass('active').siblings().removeClass('active');
|
||||||
|
var period = link.attr('data-period');
|
||||||
|
loadChartData(period);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('a[data-period="' + defaultPeriod + '"]').addClass('active').siblings().removeClass('active');
|
||||||
|
});
|
265
webroot/js/mining-inflation-chart.js
Normal file
265
webroot/js/mining-inflation-chart.js
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
function getReward(blockHeight) {
|
||||||
|
if (blockHeight == 0) {
|
||||||
|
return 400000000;
|
||||||
|
}
|
||||||
|
else if (blockHeight <= 5100) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (blockHeight <= 55000) {
|
||||||
|
return 1 + Math.floor((blockHeight - 5001) / 100);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var level = Math.floor((blockHeight - 55001) / 32);
|
||||||
|
var reduction = Math.floor((Math.floor(Math.sqrt((8 * level) + 1)) - 1) / 2);
|
||||||
|
while(!(withinLevelBounds(reduction, level))) {
|
||||||
|
if(Math.floor((reduction * reduction + reduction) / 2) > level) {
|
||||||
|
reduction--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reduction++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.max(0, 500 - reduction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function withinLevelBounds(reduction, level) {
|
||||||
|
if(Math.floor((reduction * reduction + reduction) / 2) > level) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
reduction += 1;
|
||||||
|
if(Math.floor((reduction * reduction + reduction) / 2) <= level) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAverageBlockTime(blocks) {
|
||||||
|
var numBlocks = blocks.length;
|
||||||
|
var windowSize = 100;
|
||||||
|
var sum = 0;
|
||||||
|
for(i = numBlocks - windowSize; i < numBlocks; i++) {
|
||||||
|
sum += blocks[i].block_time - blocks[i-1].block_time;
|
||||||
|
}
|
||||||
|
return sum / windowSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildChartData(blockData) {
|
||||||
|
var chartData = [];
|
||||||
|
var supply = 0;
|
||||||
|
var reward = 0;
|
||||||
|
var averageBlockTime = getAverageBlockTime(blockData);
|
||||||
|
var blockTime = 0;
|
||||||
|
var lastBlock = 4071017; // Last block with reward
|
||||||
|
var skip = 100;
|
||||||
|
var blocksPerYear = Math.floor((3600*24*365) / averageBlockTime);
|
||||||
|
var historicalSupply = {};
|
||||||
|
var lastYearSupply = 0;
|
||||||
|
var lastYearBlock = 0;
|
||||||
|
var inflationRate = 0;
|
||||||
|
for(var i = 0; i < lastBlock; i++) {
|
||||||
|
reward = getReward(i);
|
||||||
|
supply += reward;
|
||||||
|
historicalSupply[i + 1] = supply;
|
||||||
|
if(i == 0) { // Reward for 1st block set to 0 for scale
|
||||||
|
reward = 0;
|
||||||
|
}
|
||||||
|
if(i < blockData.length) {
|
||||||
|
// Historical Data
|
||||||
|
var b = blockData[i];
|
||||||
|
blockTime = b.block_time;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Future blocks
|
||||||
|
skip = 1000;
|
||||||
|
blockTime += averageBlockTime;
|
||||||
|
}
|
||||||
|
// Inflation Rate
|
||||||
|
if(i + 1 - blocksPerYear <= 0) {
|
||||||
|
lastYearBlock = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastYearBlock = i + 1 - blocksPerYear;
|
||||||
|
}
|
||||||
|
lastYearSupply = historicalSupply[lastYearBlock];
|
||||||
|
inflationRate = ((supply - lastYearSupply) / lastYearSupply) * 100;
|
||||||
|
if(i % skip == 0) { // Only push 1/<skip> of all blocks to optimize data loading
|
||||||
|
chartData.push({
|
||||||
|
date: new Date(blockTime * 1000),
|
||||||
|
date: new Date(blockTime * 1000),
|
||||||
|
AvailableSupply: supply,
|
||||||
|
RewardLBC: reward,
|
||||||
|
InflationRate: inflationRate,
|
||||||
|
BlockId: i + 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chartData;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadChartData() {
|
||||||
|
var api_url = "https://chainquery.lbry.io/api/sql?query=";
|
||||||
|
var query = "SELECT id, block_time FROM block";
|
||||||
|
var url = api_url + query;
|
||||||
|
var loadProgress = $('.mining-inflation-chart-container .load-progress');
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
type: 'get',
|
||||||
|
dataType: 'json',
|
||||||
|
beforeSend: function() {
|
||||||
|
chartLoadInProgress = true;
|
||||||
|
loadProgress.css({ display: 'block' });
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if(response.success) {
|
||||||
|
chartData = buildChartData(response.data);
|
||||||
|
if(chart) {
|
||||||
|
chart.dataProvider = chartData;
|
||||||
|
chart.validateNow();
|
||||||
|
chart.validateData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("Could not fetch block data.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
chartLoadInProgress = false;
|
||||||
|
loadProgress.css({ display: 'none' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var chart;
|
||||||
|
var chartData = [];
|
||||||
|
var chartLoadInProgress = false;
|
||||||
|
AmCharts.ready(function() {
|
||||||
|
chart = AmCharts.makeChart('mining-inflation-chart', {
|
||||||
|
type: 'serial',
|
||||||
|
theme: 'light',
|
||||||
|
mouseWheelZoomEnabled: true,
|
||||||
|
height: '100%',
|
||||||
|
categoryField: 'date',
|
||||||
|
synchronizeGrid: true,
|
||||||
|
dataProvider: chartData,
|
||||||
|
responsive: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
valueAxes: [
|
||||||
|
{
|
||||||
|
id: 'v-supply',
|
||||||
|
axisColor: '#1e88e5',
|
||||||
|
axisThickness: 2,
|
||||||
|
position: 'left',
|
||||||
|
labelFunction: function(value) {
|
||||||
|
return (Math.round((value / 1000000) * 1000000)/1000000).toFixed(2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v-reward',
|
||||||
|
axisColor: '#0b7a06',
|
||||||
|
axisThickness: 2,
|
||||||
|
position: 'left',
|
||||||
|
offset: 75,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'v-inflation-rate',
|
||||||
|
axisColor: '#ff9900',
|
||||||
|
axisThickness: 2,
|
||||||
|
position: 'right',
|
||||||
|
labelFunction: function(value) {
|
||||||
|
return value.toFixed(2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
categoryAxis: {
|
||||||
|
parseDates: true,
|
||||||
|
autoGridCount: false,
|
||||||
|
minorGridEnabled: true,
|
||||||
|
minorGridAlpha: 0.04,
|
||||||
|
axisColor: '#dadada',
|
||||||
|
twoLineMode: true
|
||||||
|
},
|
||||||
|
graphs: [
|
||||||
|
{
|
||||||
|
id: 'g-supply',
|
||||||
|
valueAxis: 'v-supply', // we have to indicate which value axis should be used
|
||||||
|
title: 'Available supply (millions LBC)',
|
||||||
|
valueField: 'AvailableSupply',
|
||||||
|
bullet: 'round',
|
||||||
|
bulletBorderThickness: 1,
|
||||||
|
bulletBorderAlpha: 1,
|
||||||
|
bulletColor: '#ffffff',
|
||||||
|
bulletSize: 5,
|
||||||
|
useLineColorForBulletBorder: true,
|
||||||
|
lineColor: '#1e88e5',
|
||||||
|
hideBulletsCount: 101,
|
||||||
|
balloonText: '[[AvailableSupply]]',
|
||||||
|
balloonFunction: function(item, graph) {
|
||||||
|
var result = graph.balloonText;
|
||||||
|
return result.replace('[[AvailableSupply]]', (Math.round((item.dataContext.AvailableSupply / 1000000) * 1000000)/1000000).toFixed(2));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'g-reward',
|
||||||
|
valueAxis: 'v-reward',
|
||||||
|
title: 'Block Reward (LBC)',
|
||||||
|
valueField: 'RewardLBC',
|
||||||
|
bullet: 'round',
|
||||||
|
bulletBorderThickness: 1,
|
||||||
|
bulletBorderAlpha: 1,
|
||||||
|
bulletColor: '#ffffff',
|
||||||
|
bulletSize: 5,
|
||||||
|
useLineColorForBulletBorder: true,
|
||||||
|
lineColor: '#0b7a06',
|
||||||
|
balloonText: '[[RewardLBC]] LBC<br>Block [[BlockId]]',
|
||||||
|
hideBulletsCount: 101
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'g-inflation-rate',
|
||||||
|
valueAxis: 'v-inflation-rate',
|
||||||
|
title: 'Annualized Inflation Rate',
|
||||||
|
valueField: 'InflationRate',
|
||||||
|
bullet: 'round',
|
||||||
|
bulletBorderThickness: 1,
|
||||||
|
bulletBorderAlpha: 1,
|
||||||
|
bulletColor: '#ffffff',
|
||||||
|
bulletSize: 5,
|
||||||
|
useLineColorForBulletBorder: true,
|
||||||
|
lineColor: '#ff9900',
|
||||||
|
balloonText: '[[InflationRate]]%',
|
||||||
|
hideBulletsCount: 101,
|
||||||
|
balloonFunction: function(item, graph) {
|
||||||
|
var result = graph.balloonText;
|
||||||
|
return result.replace('[[InflationRate]]', item.dataContext.InflationRate.toFixed(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
chartCursor: {
|
||||||
|
cursorAlpha: 0.1,
|
||||||
|
fullWidth: true,
|
||||||
|
valueLineBalloonEnabled: true,
|
||||||
|
categoryBalloonColor: '#333333',
|
||||||
|
cursorColor: '#1e88e5'
|
||||||
|
},
|
||||||
|
chartScrollbar: {
|
||||||
|
scrollbarHeight: 36,
|
||||||
|
color: '#888888',
|
||||||
|
gridColor: '#bbbbbb'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
marginLeft: 110,
|
||||||
|
useGraphSettings: true,
|
||||||
|
valueText: "",
|
||||||
|
spacing: 64,
|
||||||
|
|
||||||
|
},
|
||||||
|
export: {
|
||||||
|
enabled: true,
|
||||||
|
fileName: 'lbry-supply-chart',
|
||||||
|
position: 'bottom-right',
|
||||||
|
divId: 'chart-export'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
loadChartData();
|
||||||
|
});
|
Loading…
Reference in a new issue