mirror of
https://github.com/mempool/mempool.git
synced 2025-02-25 07:07:36 +01:00
Add share % in pie chart label
This commit is contained in:
parent
5b32ab6dde
commit
8eaa9b3c7b
4 changed files with 93 additions and 82 deletions
|
@ -9,8 +9,7 @@
|
|||
|
||||
<div class="card-header">
|
||||
<form [formGroup]="radioGroupForm" class="formRadioGroup">
|
||||
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan"
|
||||
(change)="onChangeWindowPreference($event)">
|
||||
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
|
||||
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||
<input ngbButton type="radio" [value]="'1d'" [routerLink]="['/pools' | relativeUrl]" fragment="1d"> 1D
|
||||
</label>
|
||||
|
@ -54,7 +53,7 @@
|
|||
<th i18n="latest-blocks.mined">Block Count (%)</th>
|
||||
<th class="d-none d-md-block" i18n="latest-blocks.transactions">Empty Blocks (%)</th>
|
||||
</thead>
|
||||
<tbody *ngIf="(miningStatsEmitter$ | async) as miningStats">
|
||||
<tbody *ngIf="(miningStatsObservable$ | async) as miningStats">
|
||||
<tr>
|
||||
<td class="d-none d-md-block">-</td>
|
||||
<td><!-- LOGO --></td>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { EChartsOption } from 'echarts';
|
||||
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||
import { StateService } from 'src/app/services/state.service';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { catchError, skip, startWith, switchMap, tap } from 'rxjs/operators';
|
||||
import { StorageService } from '../..//services/storage.service';
|
||||
import { MiningService, MiningStats } from '../../services/mining.service';
|
||||
import { StateService } from '../../services/state.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pool-ranking',
|
||||
|
@ -22,79 +23,74 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
|
|||
poolsWindowPreference: string;
|
||||
radioGroupForm: FormGroup;
|
||||
|
||||
miningStats!: MiningStats;
|
||||
miningStatsEmitter$ = new BehaviorSubject<MiningStats>(this.miningStats);
|
||||
blocksSubscription: Subscription;
|
||||
miningSubscription: Subscription;
|
||||
|
||||
isLoading = true;
|
||||
chartOptions: EChartsOption = {};
|
||||
chartInitOptions = {
|
||||
renderer: 'svg'
|
||||
};
|
||||
|
||||
miningStatsObservable$: Observable<MiningStats>;
|
||||
|
||||
constructor(
|
||||
private stateService: StateService,
|
||||
private storageService: StorageService,
|
||||
private formBuilder: FormBuilder,
|
||||
private miningService: MiningService,
|
||||
) {
|
||||
this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference').trim() : '2h';
|
||||
|
||||
this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1d';
|
||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
|
||||
this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.refreshMiningStats();
|
||||
this.watchBlocks();
|
||||
// When...
|
||||
this.miningStatsObservable$ = combineLatest([
|
||||
// ...a new block is mined
|
||||
this.stateService.blocks$
|
||||
.pipe(
|
||||
// (we always receives some blocks at start so only trigger for the last one)
|
||||
skip(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT - 1),
|
||||
),
|
||||
// ...or we change the timespan
|
||||
this.radioGroupForm.get('dateSpan').valueChanges
|
||||
.pipe(
|
||||
startWith(this.poolsWindowPreference), // (trigger when the page loads)
|
||||
tap((value) => {
|
||||
this.storageService.setValue('poolsWindowPreference', value);
|
||||
this.poolsWindowPreference = value;
|
||||
})
|
||||
)
|
||||
])
|
||||
// ...then refresh the mining stats
|
||||
.pipe(
|
||||
switchMap(() => {
|
||||
this.isLoading = true;
|
||||
return this.miningService.getMiningStats(this.getSQLInterval(this.poolsWindowPreference))
|
||||
.pipe(
|
||||
catchError((e) => of(this.getEmptyMiningStat()))
|
||||
);
|
||||
}),
|
||||
tap(data => {
|
||||
this.isLoading = false;
|
||||
this.prepareChartOptions(data);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.blocksSubscription.unsubscribe();
|
||||
this.miningSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
refreshMiningStats() {
|
||||
this.miningSubscription = this.miningService.getMiningStats(this.getSQLInterval(this.poolsWindowPreference))
|
||||
.subscribe(async data => {
|
||||
this.miningStats = data;
|
||||
this.miningStatsEmitter$.next(this.miningStats);
|
||||
this.prepareChartOptions();
|
||||
this.isLoading = false;
|
||||
});
|
||||
|
||||
return this.miningSubscription;
|
||||
}
|
||||
|
||||
watchBlocks() {
|
||||
this.blocksSubscription = this.stateService.blocks$
|
||||
.subscribe(() => {
|
||||
if (!this.miningStats) {
|
||||
return;
|
||||
}
|
||||
this.refreshMiningStats();
|
||||
});
|
||||
}
|
||||
|
||||
onChangeWindowPreference(e) {
|
||||
this.storageService.setValue('poolsWindowPreference', e.target.value);
|
||||
this.poolsWindowPreference = e.target.value;
|
||||
this.isLoading = true;
|
||||
this.refreshMiningStats();
|
||||
}
|
||||
|
||||
generatePoolsChartSerieData() {
|
||||
generatePoolsChartSerieData(miningStats) {
|
||||
const poolShareThreshold = 0.5; // Do not draw pools which hashrate share is lower than that
|
||||
const data: object[] = [];
|
||||
|
||||
this.miningStats.pools.forEach((pool) => {
|
||||
miningStats.pools.forEach((pool) => {
|
||||
if (parseFloat(pool.share) < poolShareThreshold) {
|
||||
return;
|
||||
}
|
||||
data.push({
|
||||
value: pool.share,
|
||||
name: pool.name,
|
||||
name: pool.name + ` (${pool.share}%)`,
|
||||
label: { color: '#FFFFFF' },
|
||||
tooltip: {
|
||||
formatter: () => {
|
||||
|
@ -113,7 +109,7 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
|
|||
return data;
|
||||
}
|
||||
|
||||
prepareChartOptions() {
|
||||
prepareChartOptions(miningStats) {
|
||||
this.chartOptions = {
|
||||
title: {
|
||||
text: (this.poolsWindowPreference === '1d') ? 'Hashrate distribution' : 'Block distribution',
|
||||
|
@ -143,7 +139,7 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
|
|||
name: 'Mining pool',
|
||||
type: 'pie',
|
||||
radius: ['30%', '70%'],
|
||||
data: this.generatePoolsChartSerieData(),
|
||||
data: this.generatePoolsChartSerieData(miningStats),
|
||||
labelLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
|
@ -193,5 +189,21 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default mining stats if something goes wrong
|
||||
*/
|
||||
getEmptyMiningStat() {
|
||||
return {
|
||||
lastEstimatedHashrate: 'Error',
|
||||
blockCount: 0,
|
||||
totalEmptyBlock: 0,
|
||||
totalEmptyBlockRatio: '',
|
||||
pools: [],
|
||||
miningUnits: {
|
||||
hashrateDivider: 1,
|
||||
hashrateUnit: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,22 +53,22 @@ export interface LiquidPegs {
|
|||
export interface ITranslators { [language: string]: string; }
|
||||
|
||||
export interface SinglePoolStats {
|
||||
pooldId: number,
|
||||
name: string,
|
||||
link: string,
|
||||
blockCount: number,
|
||||
emptyBlocks: number,
|
||||
rank: number,
|
||||
share: string,
|
||||
lastEstimatedHashrate: string,
|
||||
emptyBlockRatio: string,
|
||||
logo: string,
|
||||
pooldId: number;
|
||||
name: string;
|
||||
link: string;
|
||||
blockCount: number;
|
||||
emptyBlocks: number;
|
||||
rank: number;
|
||||
share: string;
|
||||
lastEstimatedHashrate: string;
|
||||
emptyBlockRatio: string;
|
||||
logo: string;
|
||||
}
|
||||
|
||||
export interface PoolsStats {
|
||||
blockCount: number,
|
||||
lastEstimatedHashrate: number,
|
||||
pools: SinglePoolStats[],
|
||||
blockCount: number;
|
||||
lastEstimatedHashrate: number;
|
||||
pools: SinglePoolStats[];
|
||||
}
|
||||
|
||||
export interface ITranslators { [language: string]: string; }
|
||||
|
|
|
@ -6,17 +6,17 @@ import { ApiService } from '../services/api.service';
|
|||
import { StateService } from './state.service';
|
||||
|
||||
export interface MiningUnits {
|
||||
hashrateDivider: number,
|
||||
hashrateUnit: string,
|
||||
hashrateDivider: number;
|
||||
hashrateUnit: string;
|
||||
}
|
||||
|
||||
export interface MiningStats {
|
||||
lastEstimatedHashrate: string,
|
||||
blockCount: number,
|
||||
totalEmptyBlock: number,
|
||||
totalEmptyBlockRatio: string,
|
||||
pools: SinglePoolStats[],
|
||||
miningUnits: MiningUnits,
|
||||
lastEstimatedHashrate: string;
|
||||
blockCount: number;
|
||||
totalEmptyBlock: number;
|
||||
totalEmptyBlockRatio: string;
|
||||
pools: SinglePoolStats[];
|
||||
miningUnits: MiningUnits;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
|
@ -38,15 +38,15 @@ export class MiningService {
|
|||
/**
|
||||
* Set the hashrate power of ten we want to display
|
||||
*/
|
||||
public getMiningUnits() : MiningUnits {
|
||||
public getMiningUnits(): MiningUnits {
|
||||
const powerTable = {
|
||||
0: "H/s",
|
||||
3: "kH/s",
|
||||
6: "MH/s",
|
||||
9: "GH/s",
|
||||
12: "TH/s",
|
||||
15: "PH/s",
|
||||
18: "EH/s",
|
||||
0: 'H/s',
|
||||
3: 'kH/s',
|
||||
6: 'MH/s',
|
||||
9: 'GH/s',
|
||||
12: 'TH/s',
|
||||
15: 'PH/s',
|
||||
18: 'EH/s',
|
||||
};
|
||||
|
||||
// I think it's fine to hardcode this since we don't have x1000 hashrate jump everyday
|
||||
|
@ -62,7 +62,7 @@ export class MiningService {
|
|||
};
|
||||
}
|
||||
|
||||
private generateMiningStats(stats: PoolsStats) : MiningStats {
|
||||
private generateMiningStats(stats: PoolsStats): MiningStats {
|
||||
const miningUnits = this.getMiningUnits();
|
||||
const hashrateDivider = miningUnits.hashrateDivider;
|
||||
|
||||
|
@ -77,7 +77,7 @@ export class MiningService {
|
|||
emptyBlockRatio: (poolStat.emptyBlocks / poolStat.blockCount * 100).toFixed(2),
|
||||
logo: `./resources/mining-pools/` + poolStat.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg',
|
||||
...poolStat
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
Loading…
Add table
Reference in a new issue