Add USD serie in block fee/reward charts
This commit is contained in:
@@ -13,6 +13,7 @@ import { SharedModule } from './shared/shared.module';
|
||||
import { StorageService } from './services/storage.service';
|
||||
import { HttpCacheInterceptor } from './services/http-cache.interceptor';
|
||||
import { LanguageService } from './services/language.service';
|
||||
import { FiatShortenerPipe } from './shared/pipes/fiat-shortener.pipe';
|
||||
import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe';
|
||||
import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe';
|
||||
|
||||
@@ -37,6 +38,7 @@ import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe
|
||||
StorageService,
|
||||
LanguageService,
|
||||
ShortenStringPipe,
|
||||
FiatShortenerPipe,
|
||||
CapAddressPipe,
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }
|
||||
],
|
||||
|
||||
@@ -180,8 +180,8 @@ export class BlockFeeRatesGraphComponent implements OnInit {
|
||||
}
|
||||
let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}</b><br>`;
|
||||
|
||||
for (const pool of data.reverse()) {
|
||||
tooltip += `${pool.marker} ${pool.seriesName}: ${pool.data[1]} sats/vByte<br>`;
|
||||
for (const rate of data.reverse()) {
|
||||
tooltip += `${rate.marker} ${rate.seriesName}: ${rate.data[1]} sats/vByte<br>`;
|
||||
}
|
||||
|
||||
if (['24h', '3d'].includes(this.timespan)) {
|
||||
|
||||
@@ -4,12 +4,13 @@ import { Observable } from 'rxjs';
|
||||
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
|
||||
import { ApiService } from 'src/app/services/api.service';
|
||||
import { SeoService } from 'src/app/services/seo.service';
|
||||
import { formatNumber } from '@angular/common';
|
||||
import { formatCurrency, formatNumber, getCurrencySymbol } from '@angular/common';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { download, formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils';
|
||||
import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from 'src/app/shared/graphs.utils';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { MiningService } from 'src/app/services/mining.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { FiatShortenerPipe } from 'src/app/shared/pipes/fiat-shortener.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-block-fees-graph',
|
||||
@@ -51,6 +52,7 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||
private storageService: StorageService,
|
||||
private miningService: MiningService,
|
||||
private route: ActivatedRoute,
|
||||
private fiatShortenerPipe: FiatShortenerPipe,
|
||||
) {
|
||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
||||
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
||||
@@ -82,6 +84,7 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||
tap((response) => {
|
||||
this.prepareChartOptions({
|
||||
blockFees: response.body.map(val => [val.timestamp * 1000, val.avgFees / 100000000, val.avgHeight]),
|
||||
blockFeesUSD: response.body.filter(val => val.usd > 0).map(val => [val.timestamp * 1000, val.avgFees / 100000000 * val.usd, val.avgHeight]),
|
||||
});
|
||||
this.isLoading = false;
|
||||
}),
|
||||
@@ -98,16 +101,17 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||
|
||||
prepareChartOptions(data) {
|
||||
this.chartOptions = {
|
||||
animation: false,
|
||||
color: [
|
||||
new graphic.LinearGradient(0, 0, 0, 0.65, [
|
||||
{ offset: 0, color: '#F4511E' },
|
||||
{ offset: 0.25, color: '#FB8C00' },
|
||||
{ offset: 0.5, color: '#FFB300' },
|
||||
{ offset: 0.75, color: '#FDD835' },
|
||||
{ offset: 1, color: '#7CB342' }
|
||||
new graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#00ACC1' },
|
||||
{ offset: 1, color: '#0D47A1' },
|
||||
]),
|
||||
new graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#FDD835' },
|
||||
{ offset: 1, color: '#FB8C00' },
|
||||
]),
|
||||
],
|
||||
animation: false,
|
||||
grid: {
|
||||
top: 30,
|
||||
bottom: 80,
|
||||
@@ -128,28 +132,52 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||
align: 'left',
|
||||
},
|
||||
borderColor: '#000',
|
||||
formatter: (ticks) => {
|
||||
let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10))}</b><br>`;
|
||||
tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1], this.locale, '1.3-3')} BTC`;
|
||||
tooltip += `<br>`;
|
||||
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>`;
|
||||
|
||||
if (['24h', '3d'].includes(this.timespan)) {
|
||||
tooltip += `<small>` + $localize`At block: ${ticks[0].data[2]}` + `</small>`;
|
||||
} else {
|
||||
tooltip += `<small>` + $localize`Around block: ${ticks[0].data[2]}` + `</small>`;
|
||||
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) {
|
||||
tooltip += `${tick.marker} ${tick.seriesName}: ${formatCurrency(tick.data[1], this.locale, getCurrencySymbol('USD', 'narrow'), 'USD', '1.0-0')}<br>`;
|
||||
}
|
||||
}
|
||||
|
||||
tooltip += `<small>* On average around block ${data[0].data[2]}</small>`;
|
||||
return tooltip;
|
||||
}
|
||||
}.bind(this)
|
||||
},
|
||||
xAxis: {
|
||||
name: formatterXAxisLabel(this.locale, this.timespan),
|
||||
nameLocation: 'middle',
|
||||
nameTextStyle: {
|
||||
padding: [10, 0, 0, 0],
|
||||
},
|
||||
xAxis: data.blockFees.length === 0 ? undefined :
|
||||
{
|
||||
type: 'time',
|
||||
splitNumber: this.isMobile() ? 5 : 10,
|
||||
axisLabel: {
|
||||
hideOverlap: true,
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: [
|
||||
{
|
||||
name: 'Fees BTC',
|
||||
inactiveColor: 'rgb(110, 112, 121)',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
icon: 'roundRect',
|
||||
},
|
||||
{
|
||||
name: 'Fees USD',
|
||||
inactiveColor: 'rgb(110, 112, 121)',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
icon: 'roundRect',
|
||||
},
|
||||
],
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
@@ -160,6 +188,9 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||
return `${val} BTC`;
|
||||
}
|
||||
},
|
||||
max: (value) => {
|
||||
return Math.floor(value.max * 2 * 10) / 10;
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dotted',
|
||||
@@ -168,18 +199,47 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
position: 'right',
|
||||
axisLabel: {
|
||||
color: 'rgb(110, 112, 121)',
|
||||
formatter: function(val) {
|
||||
return this.fiatShortenerPipe.transform(val);
|
||||
}.bind(this)
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
legendHoverLink: false,
|
||||
zlevel: 0,
|
||||
name: $localize`:@@c20172223f84462032664d717d739297e5a9e2fe:Fees`,
|
||||
showSymbol: false,
|
||||
symbol: 'none',
|
||||
yAxisIndex: 0,
|
||||
name: 'Fees BTC',
|
||||
data: data.blockFees,
|
||||
type: 'line',
|
||||
smooth: 0.25,
|
||||
symbol: 'none',
|
||||
areaStyle: {
|
||||
opacity: 0.25,
|
||||
},
|
||||
},
|
||||
{
|
||||
legendHoverLink: false,
|
||||
zlevel: 1,
|
||||
yAxisIndex: 1,
|
||||
name: 'Fees USD',
|
||||
data: data.blockFeesUSD,
|
||||
type: 'line',
|
||||
smooth: 0.25,
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
opacity: 0.75,
|
||||
}
|
||||
},
|
||||
],
|
||||
dataZoom: [{
|
||||
|
||||
@@ -4,12 +4,13 @@ import { Observable } from 'rxjs';
|
||||
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
|
||||
import { ApiService } from 'src/app/services/api.service';
|
||||
import { SeoService } from 'src/app/services/seo.service';
|
||||
import { formatNumber } from '@angular/common';
|
||||
import { formatCurrency, formatNumber, getCurrencySymbol } from '@angular/common';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { download, formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils';
|
||||
import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from 'src/app/shared/graphs.utils';
|
||||
import { MiningService } from 'src/app/services/mining.service';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { FiatShortenerPipe } from 'src/app/shared/pipes/fiat-shortener.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-block-rewards-graph',
|
||||
@@ -51,6 +52,7 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||
private miningService: MiningService,
|
||||
private storageService: StorageService,
|
||||
private route: ActivatedRoute,
|
||||
private fiatShortenerPipe: FiatShortenerPipe,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -80,6 +82,7 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||
tap((response) => {
|
||||
this.prepareChartOptions({
|
||||
blockRewards: response.body.map(val => [val.timestamp * 1000, val.avgRewards / 100000000, val.avgHeight]),
|
||||
blockRewardsUSD: response.body.filter(val => val.usd > 0).map(val => [val.timestamp * 1000, val.avgRewards / 100000000 * val.usd, val.avgHeight]),
|
||||
});
|
||||
this.isLoading = false;
|
||||
}),
|
||||
@@ -95,15 +98,18 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||
}
|
||||
|
||||
prepareChartOptions(data) {
|
||||
const scaleFactor = 0.1;
|
||||
|
||||
this.chartOptions = {
|
||||
animation: false,
|
||||
color: [
|
||||
new graphic.LinearGradient(0, 0, 0, 0.65, [
|
||||
{ offset: 0, color: '#F4511E' },
|
||||
{ offset: 0.25, color: '#FB8C00' },
|
||||
{ offset: 0.5, color: '#FFB300' },
|
||||
{ offset: 0.75, color: '#FDD835' },
|
||||
{ offset: 1, color: '#7CB342' }
|
||||
new graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#00ACC1' },
|
||||
{ offset: 1, color: '#0D47A1' },
|
||||
]),
|
||||
new graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#FDD835' },
|
||||
{ offset: 1, color: '#FB8C00' },
|
||||
]),
|
||||
],
|
||||
grid: {
|
||||
@@ -126,33 +132,55 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||
align: 'left',
|
||||
},
|
||||
borderColor: '#000',
|
||||
formatter: (ticks) => {
|
||||
let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10))}</b><br>`;
|
||||
tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1], this.locale, '1.3-3')} BTC`;
|
||||
tooltip += `<br>`;
|
||||
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>`;
|
||||
|
||||
if (['24h', '3d'].includes(this.timespan)) {
|
||||
tooltip += `<small>` + $localize`At block: ${ticks[0].data[2]}` + `</small>`;
|
||||
} else {
|
||||
tooltip += `<small>` + $localize`Around block: ${ticks[0].data[2]}` + `</small>`;
|
||||
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) {
|
||||
tooltip += `${tick.marker} ${tick.seriesName}: ${formatCurrency(tick.data[1], this.locale, getCurrencySymbol('USD', 'narrow'), 'USD', '1.0-0')}<br>`;
|
||||
}
|
||||
}
|
||||
|
||||
tooltip += `<small>* On average around block ${data[0].data[2]}</small>`;
|
||||
return tooltip;
|
||||
}
|
||||
}.bind(this)
|
||||
},
|
||||
xAxis: {
|
||||
name: formatterXAxisLabel(this.locale, this.timespan),
|
||||
nameLocation: 'middle',
|
||||
nameTextStyle: {
|
||||
padding: [10, 0, 0, 0],
|
||||
},
|
||||
xAxis: data.blockRewards.length === 0 ? undefined :
|
||||
{
|
||||
type: 'time',
|
||||
splitNumber: this.isMobile() ? 5 : 10,
|
||||
axisLabel: {
|
||||
hideOverlap: true,
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: [
|
||||
{
|
||||
name: 'Rewards BTC',
|
||||
inactiveColor: 'rgb(110, 112, 121)',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
icon: 'roundRect',
|
||||
},
|
||||
{
|
||||
name: 'Rewards USD',
|
||||
inactiveColor: 'rgb(110, 112, 121)',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
},
|
||||
icon: 'roundRect',
|
||||
},
|
||||
],
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
min: value => Math.round(10 * value.min * 0.99) / 10,
|
||||
max: value => Math.round(10 * value.max * 1.01) / 10,
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
color: 'rgb(110, 112, 121)',
|
||||
@@ -160,6 +188,12 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||
return `${val} BTC`;
|
||||
}
|
||||
},
|
||||
min: (value) => {
|
||||
return Math.round(value.min * (1.0 - scaleFactor) * 10) / 10;
|
||||
},
|
||||
max: (value) => {
|
||||
return Math.round(value.max * (1.0 + scaleFactor) * 10) / 10;
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dotted',
|
||||
@@ -168,18 +202,53 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
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) {
|
||||
return this.fiatShortenerPipe.transform(val);
|
||||
}.bind(this)
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
legendHoverLink: false,
|
||||
zlevel: 0,
|
||||
name: $localize`:@@12f86e6747a5ad39e62d3480ddc472b1aeab5b76:Reward`,
|
||||
showSymbol: false,
|
||||
symbol: 'none',
|
||||
yAxisIndex: 0,
|
||||
name: 'Rewards BTC',
|
||||
data: data.blockRewards,
|
||||
type: 'line',
|
||||
smooth: 0.25,
|
||||
symbol: 'none',
|
||||
areaStyle: {
|
||||
opacity: 0.25,
|
||||
},
|
||||
},
|
||||
{
|
||||
legendHoverLink: false,
|
||||
zlevel: 1,
|
||||
yAxisIndex: 1,
|
||||
name: 'Rewards USD',
|
||||
data: data.blockRewardsUSD,
|
||||
type: 'line',
|
||||
smooth: 0.25,
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
opacity: 0.75,
|
||||
}
|
||||
},
|
||||
],
|
||||
dataZoom: [{
|
||||
|
||||
@@ -351,6 +351,7 @@ export class HashrateChartComponent implements OnInit {
|
||||
series: data.hashrates.length === 0 ? [] : [
|
||||
{
|
||||
zlevel: 0,
|
||||
yAxisIndex: 0,
|
||||
name: $localize`:@@79a9dc5b1caca3cbeb1733a19515edacc5fc7920:Hashrate`,
|
||||
showSymbol: false,
|
||||
symbol: 'none',
|
||||
|
||||
37
frontend/src/app/shared/pipes/fiat-shortener.pipe.ts
Normal file
37
frontend/src/app/shared/pipes/fiat-shortener.pipe.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { formatCurrency, getCurrencySymbol } from '@angular/common';
|
||||
import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'fiatShortener'
|
||||
})
|
||||
export class FiatShortenerPipe implements PipeTransform {
|
||||
constructor(
|
||||
@Inject(LOCALE_ID) public locale: string
|
||||
) {}
|
||||
|
||||
transform(num: number, ...args: any[]): unknown {
|
||||
const digits = args[0] || 1;
|
||||
const unit = args[1] || undefined;
|
||||
|
||||
if (num < 1000) {
|
||||
return num.toFixed(digits);
|
||||
}
|
||||
|
||||
const lookup = [
|
||||
{ value: 1, symbol: '' },
|
||||
{ value: 1e3, symbol: 'k' },
|
||||
{ value: 1e6, symbol: 'M' },
|
||||
{ value: 1e9, symbol: 'G' },
|
||||
{ value: 1e12, symbol: 'T' },
|
||||
{ value: 1e15, symbol: 'P' },
|
||||
{ value: 1e18, symbol: 'E' }
|
||||
];
|
||||
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||
const item = lookup.slice().reverse().find((item) => num >= item.value);
|
||||
|
||||
let result = item ? (num / item.value).toFixed(digits).replace(rx, '$1') : '0';
|
||||
result = formatCurrency(parseInt(result, 10), this.locale, getCurrencySymbol('USD', 'narrow'), 'USD', '1.0-0');
|
||||
|
||||
return result + item.symbol;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user