2022-06-15 11:26:58 +02:00
import { ChangeDetectionStrategy , Component , Inject , Input , LOCALE_ID , OnInit } from '@angular/core' ;
2023-11-06 18:19:54 +00:00
import { echarts , EChartsOption } from '../../graphs/echarts' ;
2023-02-23 15:06:57 +09:00
import { Observable } from 'rxjs' ;
2022-04-11 20:57:13 +09:00
import { map , share , startWith , switchMap , tap } from 'rxjs/operators' ;
2022-09-21 17:23:45 +02:00
import { ApiService } from '../../services/api.service' ;
import { SeoService } from '../../services/seo.service' ;
2023-01-03 11:58:51 -06:00
import { formatNumber } from '@angular/common' ;
2022-11-28 11:55:23 +09:00
import { UntypedFormBuilder , UntypedFormGroup } from '@angular/forms' ;
2023-02-23 15:06:57 +09:00
import { download , formatterXAxis } from '../../shared/graphs.utils' ;
2022-09-21 17:23:45 +02:00
import { MiningService } from '../../services/mining.service' ;
import { StorageService } from '../../services/storage.service' ;
2022-06-15 11:26:58 +02:00
import { ActivatedRoute } from '@angular/router' ;
2022-09-21 17:23:45 +02:00
import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe' ;
2023-01-03 11:58:51 -06:00
import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe' ;
2023-11-02 01:29:55 +00:00
import { StateService } from '../../services/state.service' ;
2022-04-11 20:57:13 +09:00
@Component ( {
selector : 'app-block-rewards-graph' ,
templateUrl : './block-rewards-graph.component.html' ,
styleUrls : [ './block-rewards-graph.component.scss' ] ,
styles : [ `
. loadingGraphs {
position : absolute ;
top : 50 % ;
left : calc ( 50 % - 15 px ) ;
z - index : 100 ;
}
` ],
changeDetection : ChangeDetectionStrategy.OnPush ,
} )
export class BlockRewardsGraphComponent implements OnInit {
@Input ( ) right : number | string = 45 ;
@Input ( ) left : number | string = 75 ;
miningWindowPreference : string ;
2022-11-28 11:55:23 +09:00
radioGroupForm : UntypedFormGroup ;
2022-04-11 20:57:13 +09:00
chartOptions : EChartsOption = { } ;
chartInitOptions = {
renderer : 'svg' ,
} ;
statsObservable$ : Observable < any > ;
isLoading = true ;
formatNumber = formatNumber ;
timespan = '' ;
2022-05-05 16:18:28 +09:00
chartInstance : any = undefined ;
2022-04-11 20:57:13 +09:00
2023-01-03 11:58:51 -06:00
currency : string ;
2022-04-11 20:57:13 +09:00
constructor (
@Inject ( LOCALE_ID ) public locale : string ,
private seoService : SeoService ,
private apiService : ApiService ,
2022-11-28 11:55:23 +09:00
private formBuilder : UntypedFormBuilder ,
2022-04-11 20:57:13 +09:00
private miningService : MiningService ,
2022-06-15 11:26:58 +02:00
private storageService : StorageService ,
2023-11-02 01:29:55 +00:00
public stateService : StateService ,
2022-06-15 11:26:58 +02:00
private route : ActivatedRoute ,
2022-06-06 10:14:40 +02:00
private fiatShortenerPipe : FiatShortenerPipe ,
2023-01-03 11:58:51 -06:00
private fiatCurrencyPipe : FiatCurrencyPipe ,
2022-04-11 20:57:13 +09:00
) {
2023-02-23 15:06:57 +09:00
this . currency = 'USD' ;
2022-04-11 20:57:13 +09:00
}
ngOnInit ( ) : void {
2022-05-10 17:05:07 +04:00
this . seoService . setTitle ( $localize ` :@@8ba8fe810458280a83df7fdf4c614dfc1a826445:Block Rewards ` ) ;
2023-08-30 20:26:07 +09:00
this . seoService . setDescription ( $localize ` :@@meta.description.bitcoin.graphs.block-rewards:See Bitcoin block rewards in BTC and USD visualized over time. Block rewards are the total funds miners earn from the block subsidy and fees. ` ) ;
2022-07-11 23:16:48 +02:00
this . miningWindowPreference = this . miningService . getDefaultTimespan ( '3m' ) ;
2022-04-11 20:57:13 +09:00
this . radioGroupForm = this . formBuilder . group ( { dateSpan : this.miningWindowPreference } ) ;
this . radioGroupForm . controls . dateSpan . setValue ( this . miningWindowPreference ) ;
2022-06-15 11:26:58 +02:00
this . route
. fragment
. subscribe ( ( fragment ) = > {
2023-02-21 18:48:09 +09:00
if ( [ '1m' , '3m' , '6m' , '1y' , '2y' , '3y' , 'all' ] . indexOf ( fragment ) > - 1 ) {
2022-06-23 15:30:42 +02:00
this . radioGroupForm . controls . dateSpan . setValue ( fragment , { emitEvent : false } ) ;
2022-06-15 11:26:58 +02:00
}
} ) ;
2022-04-11 20:57:13 +09:00
this . statsObservable $ = this . radioGroupForm . get ( 'dateSpan' ) . valueChanges
. pipe (
2022-06-15 11:26:58 +02:00
startWith ( this . radioGroupForm . controls . dateSpan . value ) ,
2022-04-11 20:57:13 +09:00
switchMap ( ( timespan ) = > {
this . storageService . setValue ( 'miningWindowPreference' , timespan ) ;
this . timespan = timespan ;
this . isLoading = true ;
return this . apiService . getHistoricalBlockRewards $ ( timespan )
. pipe (
2022-04-15 20:43:10 +09:00
tap ( ( response ) = > {
2022-04-11 20:57:13 +09:00
this . prepareChartOptions ( {
2022-06-10 23:34:13 +02:00
blockRewards : response.body.map ( val = > [ val . timestamp * 1000 , val . avgRewards / 100000000 , val . avgHeight ] ) ,
2023-01-03 11:58:51 -06:00
blockRewardsFiat : response.body.filter ( val = > val [ this . currency ] > 0 ) . map ( val = > [ val . timestamp * 1000 , val . avgRewards / 100000000 * val [ this . currency ] , val . avgHeight ] ) ,
2022-04-11 20:57:13 +09:00
} ) ;
this . isLoading = false ;
} ) ,
2022-04-15 20:43:10 +09:00
map ( ( response ) = > {
2022-04-11 20:57:13 +09:00
return {
2022-04-15 20:43:10 +09:00
blockCount : parseInt ( response . headers . get ( 'x-total-count' ) , 10 ) ,
2022-04-11 20:57:13 +09:00
} ;
} ) ,
) ;
} ) ,
share ( )
) ;
}
prepareChartOptions ( data ) {
2022-07-12 08:50:07 +02:00
let title : object ;
if ( data . blockRewards . length === 0 ) {
title = {
textStyle : {
color : 'grey' ,
fontSize : 15
} ,
text : $localize ` :@@23555386d8af1ff73f297e89dd4af3f4689fb9dd:Indexing blocks ` ,
left : 'center' ,
top : 'center'
} ;
}
2022-06-06 10:14:40 +02:00
const scaleFactor = 0.1 ;
2022-04-11 20:57:13 +09:00
this . chartOptions = {
2022-07-12 08:50:07 +02:00
title : title ,
2022-04-11 20:57:13 +09:00
animation : false ,
color : [
2023-11-06 18:19:54 +00:00
new echarts . graphic . LinearGradient ( 0 , 0 , 0 , 1 , [
2022-06-06 10:14:40 +02:00
{ offset : 0 , color : '#FDD835' } ,
{ offset : 1 , color : '#FB8C00' } ,
2022-04-11 20:57:13 +09:00
] ) ,
2023-11-06 18:19:54 +00:00
new echarts . graphic . LinearGradient ( 0 , 0 , 0 , 1 , [
2022-07-11 23:16:48 +02:00
{ offset : 0 , color : '#C0CA33' } ,
{ offset : 1 , color : '#1B5E20' } ,
] ) ,
2022-04-11 20:57:13 +09:00
] ,
grid : {
top : 20 ,
bottom : 80 ,
right : this.right ,
left : this.left ,
} ,
tooltip : {
show : ! this . isMobile ( ) ,
trigger : 'axis' ,
axisPointer : {
type : 'line'
} ,
backgroundColor : 'rgba(17, 19, 31, 1)' ,
borderRadius : 4 ,
shadowColor : 'rgba(0, 0, 0, 0.5)' ,
textStyle : {
2023-01-03 05:24:14 -06:00
color : 'var(--tooltip-grey)' ,
2022-04-11 20:57:13 +09:00
align : 'left' ,
} ,
borderColor : '#000' ,
2022-06-06 10:14:40 +02:00
formatter : function ( data ) {
if ( data . length <= 0 ) {
return '' ;
}
let tooltip = ` <b style="color: white; margin-left: 2px">
$ { formatterXAxis ( this . locale , this . timespan , parseInt ( data [ 0 ] . axisValue , 10 ) ) } < / b > < br > ` ;
2022-06-10 23:34:13 +02:00
2022-06-06 10:14:40 +02:00
for ( const tick of data ) {
if ( tick . seriesIndex === 0 ) {
tooltip += ` ${ tick . marker } ${ tick . seriesName } : ${ formatNumber ( tick . data [ 1 ] , this . locale , '1.3-3' ) } BTC<br> ` ;
} else if ( tick . seriesIndex === 1 ) {
2023-01-03 11:58:51 -06:00
tooltip += ` ${ tick . marker } ${ tick . seriesName } : ${ this . fiatCurrencyPipe . transform ( tick . data [ 1 ] , null , this . currency ) } <br> ` ;
2022-06-06 10:14:40 +02:00
}
2022-06-10 23:34:13 +02:00
}
2022-06-06 10:14:40 +02:00
tooltip += ` <small>* On average around block ${ data [ 0 ] . data [ 2 ] } </small> ` ;
2022-06-10 23:34:13 +02:00
return tooltip ;
2022-06-06 10:14:40 +02:00
} . bind ( this )
2022-04-11 20:57:13 +09:00
} ,
2022-06-06 10:14:40 +02:00
xAxis : data.blockRewards.length === 0 ? undefined :
{
2022-04-11 20:57:13 +09:00
type : 'time' ,
splitNumber : this.isMobile ( ) ? 5 : 10 ,
2022-06-06 10:14:40 +02:00
axisLabel : {
hideOverlap : true ,
}
} ,
2022-07-12 08:50:07 +02:00
legend : data.blockRewards.length === 0 ? undefined : {
2022-06-06 10:14:40 +02:00
data : [
{
name : 'Rewards BTC' ,
inactiveColor : 'rgb(110, 112, 121)' ,
textStyle : {
color : 'white' ,
} ,
icon : 'roundRect' ,
} ,
{
2023-01-03 11:58:51 -06:00
name : 'Rewards ' + this . currency ,
2022-06-06 10:14:40 +02:00
inactiveColor : 'rgb(110, 112, 121)' ,
2023-08-30 20:26:07 +09:00
textStyle : {
2022-06-06 10:14:40 +02:00
color : 'white' ,
} ,
icon : 'roundRect' ,
} ,
] ,
2022-04-11 20:57:13 +09:00
} ,
2022-07-12 08:50:07 +02:00
yAxis : data.blockRewards.length === 0 ? undefined : [
2022-04-11 20:57:13 +09:00
{
type : 'value' ,
axisLabel : {
color : 'rgb(110, 112, 121)' ,
formatter : ( val ) = > {
return ` ${ val } BTC ` ;
}
} ,
2022-06-06 10:14:40 +02:00
min : ( value ) = > {
return Math . round ( value . min * ( 1.0 - scaleFactor ) * 10 ) / 10 ;
} ,
max : ( value ) = > {
return Math . round ( value . max * ( 1.0 + scaleFactor ) * 10 ) / 10 ;
} ,
2022-04-11 20:57:13 +09:00
splitLine : {
2022-04-15 00:21:38 +09:00
lineStyle : {
type : 'dotted' ,
2024-04-04 15:36:24 +09:00
color : 'var(--transparent-fg)' ,
2022-04-15 00:21:38 +09:00
opacity : 0.25 ,
}
} ,
2022-04-11 20:57:13 +09:00
} ,
2022-06-06 10:14:40 +02:00
{
min : ( value ) = > {
return Math . round ( value . min * ( 1.0 - scaleFactor ) * 10 ) / 10 ;
} ,
max : ( value ) = > {
return Math . round ( value . max * ( 1.0 + scaleFactor ) * 10 ) / 10 ;
} ,
type : 'value' ,
position : 'right' ,
axisLabel : {
color : 'rgb(110, 112, 121)' ,
formatter : function ( val ) {
2023-01-03 11:58:51 -06:00
return this . fiatShortenerPipe . transform ( val , null , this . currency ) ;
2022-06-06 10:14:40 +02:00
} . bind ( this )
} ,
splitLine : {
show : false ,
} ,
} ,
2022-04-11 20:57:13 +09:00
] ,
2022-07-12 08:50:07 +02:00
series : data.blockRewards.length === 0 ? undefined : [
2022-04-11 20:57:13 +09:00
{
2022-06-06 10:14:40 +02:00
legendHoverLink : false ,
2022-04-11 20:57:13 +09:00
zlevel : 0 ,
2022-06-06 10:14:40 +02:00
yAxisIndex : 0 ,
name : 'Rewards BTC' ,
2022-04-11 20:57:13 +09:00
data : data.blockRewards ,
type : 'line' ,
2022-06-06 10:14:40 +02:00
smooth : 0.25 ,
symbol : 'none' ,
} ,
{
legendHoverLink : false ,
zlevel : 1 ,
yAxisIndex : 1 ,
2023-01-03 11:58:51 -06:00
name : 'Rewards ' + this . currency ,
data : data.blockRewardsFiat ,
2022-06-06 10:14:40 +02:00
type : 'line' ,
smooth : 0.25 ,
symbol : 'none' ,
2022-04-11 20:57:13 +09:00
lineStyle : {
width : 2 ,
2022-06-06 10:14:40 +02:00
opacity : 0.75 ,
2022-07-11 23:16:48 +02:00
} ,
areaStyle : {
opacity : 0.05 ,
2022-06-06 10:14:40 +02:00
}
2022-04-11 20:57:13 +09:00
} ,
] ,
2022-07-12 08:50:07 +02:00
dataZoom : data.blockRewards.length === 0 ? undefined : [ {
2022-04-11 20:57:13 +09:00
type : 'inside' ,
realtime : true ,
zoomLock : true ,
maxSpan : 100 ,
2022-04-15 19:39:27 +09:00
minSpan : 5 ,
2022-04-11 20:57:13 +09:00
moveOnMouseMove : false ,
} , {
showDetail : false ,
show : true ,
type : 'slider' ,
brushSelect : false ,
realtime : true ,
left : 20 ,
right : 15 ,
selectedDataBackground : {
lineStyle : {
color : '#fff' ,
opacity : 0.45 ,
} ,
areaStyle : {
opacity : 0 ,
}
} ,
} ] ,
} ;
}
2022-05-05 16:18:28 +09:00
onChartInit ( ec ) {
this . chartInstance = ec ;
}
2022-04-11 20:57:13 +09:00
isMobile() {
return ( window . innerWidth <= 767.98 ) ;
}
2022-05-05 16:18:28 +09:00
onSaveChart() {
// @ts-ignore
const prevBottom = this . chartOptions . grid . bottom ;
const now = new Date ( ) ;
// @ts-ignore
this . chartOptions . grid . bottom = 40 ;
2024-04-04 15:36:24 +09:00
this . chartOptions . backgroundColor = 'var(--active-bg)' ;
2022-05-05 16:18:28 +09:00
this . chartInstance . setOption ( this . chartOptions ) ;
download ( this . chartInstance . getDataURL ( {
pixelRatio : 2 ,
excludeComponents : [ 'dataZoom' ] ,
2022-05-09 11:01:51 +02:00
} ) , ` block-rewards- ${ this . timespan } - ${ Math . round ( now . getTime ( ) / 1000 ) } .svg ` ) ;
2022-05-05 16:18:28 +09:00
// @ts-ignore
this . chartOptions . grid . bottom = prevBottom ;
2022-05-09 11:01:51 +02:00
this . chartOptions . backgroundColor = 'none' ;
2022-05-05 16:18:28 +09:00
this . chartInstance . setOption ( this . chartOptions ) ;
}
2022-04-11 20:57:13 +09:00
}