Add share % in pie chart label
This commit is contained in:
		
							parent
							
								
									5b32ab6dde
								
							
						
					
					
						commit
						8eaa9b3c7b
					
				@ -9,8 +9,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  <div class="card-header">
 | 
					  <div class="card-header">
 | 
				
			||||||
    <form [formGroup]="radioGroupForm" class="formRadioGroup">
 | 
					    <form [formGroup]="radioGroupForm" class="formRadioGroup">
 | 
				
			||||||
      <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan"
 | 
					      <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
 | 
				
			||||||
        (change)="onChangeWindowPreference($event)">
 | 
					 | 
				
			||||||
        <label ngbButtonLabel class="btn-primary btn-sm">
 | 
					        <label ngbButtonLabel class="btn-primary btn-sm">
 | 
				
			||||||
          <input ngbButton type="radio" [value]="'1d'" [routerLink]="['/pools' | relativeUrl]" fragment="1d"> 1D
 | 
					          <input ngbButton type="radio" [value]="'1d'" [routerLink]="['/pools' | relativeUrl]" fragment="1d"> 1D
 | 
				
			||||||
        </label>
 | 
					        </label>
 | 
				
			||||||
@ -54,7 +53,7 @@
 | 
				
			|||||||
      <th i18n="latest-blocks.mined">Block Count (%)</th>
 | 
					      <th i18n="latest-blocks.mined">Block Count (%)</th>
 | 
				
			||||||
      <th class="d-none d-md-block" i18n="latest-blocks.transactions">Empty Blocks (%)</th>
 | 
					      <th class="d-none d-md-block" i18n="latest-blocks.transactions">Empty Blocks (%)</th>
 | 
				
			||||||
    </thead>
 | 
					    </thead>
 | 
				
			||||||
    <tbody *ngIf="(miningStatsEmitter$ | async) as miningStats">
 | 
					    <tbody *ngIf="(miningStatsObservable$ | async) as miningStats">
 | 
				
			||||||
      <tr>
 | 
					      <tr>
 | 
				
			||||||
        <td class="d-none d-md-block">-</td>
 | 
					        <td class="d-none d-md-block">-</td>
 | 
				
			||||||
        <td><!-- LOGO --></td>
 | 
					        <td><!-- LOGO --></td>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
					import { Component, OnDestroy, OnInit } from '@angular/core';
 | 
				
			||||||
import { FormBuilder, FormGroup } from '@angular/forms';
 | 
					import { FormBuilder, FormGroup } from '@angular/forms';
 | 
				
			||||||
import { EChartsOption } from 'echarts';
 | 
					import { EChartsOption } from 'echarts';
 | 
				
			||||||
import { BehaviorSubject, Subscription } from 'rxjs';
 | 
					import { combineLatest, Observable, of } from 'rxjs';
 | 
				
			||||||
import { StateService } from 'src/app/services/state.service';
 | 
					import { catchError, skip, startWith, switchMap, tap } from 'rxjs/operators';
 | 
				
			||||||
import { StorageService } from 'src/app/services/storage.service';
 | 
					import { StorageService } from '../..//services/storage.service';
 | 
				
			||||||
import { MiningService, MiningStats } from '../../services/mining.service';
 | 
					import { MiningService, MiningStats } from '../../services/mining.service';
 | 
				
			||||||
 | 
					import { StateService } from '../../services/state.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-pool-ranking',
 | 
					  selector: 'app-pool-ranking',
 | 
				
			||||||
@ -22,79 +23,74 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  poolsWindowPreference: string;
 | 
					  poolsWindowPreference: string;
 | 
				
			||||||
  radioGroupForm: FormGroup;
 | 
					  radioGroupForm: FormGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  miningStats!: MiningStats;
 | 
					 | 
				
			||||||
  miningStatsEmitter$ = new BehaviorSubject<MiningStats>(this.miningStats);
 | 
					 | 
				
			||||||
  blocksSubscription: Subscription;
 | 
					 | 
				
			||||||
  miningSubscription: Subscription;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  isLoading = true;
 | 
					  isLoading = true;
 | 
				
			||||||
  chartOptions: EChartsOption = {};
 | 
					  chartOptions: EChartsOption = {};
 | 
				
			||||||
  chartInitOptions = {
 | 
					  chartInitOptions = {
 | 
				
			||||||
    renderer: 'svg'
 | 
					    renderer: 'svg'
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  miningStatsObservable$: Observable<MiningStats>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    private stateService: StateService,
 | 
					    private stateService: StateService,
 | 
				
			||||||
    private storageService: StorageService,
 | 
					    private storageService: StorageService,
 | 
				
			||||||
    private formBuilder: FormBuilder,
 | 
					    private formBuilder: FormBuilder,
 | 
				
			||||||
    private miningService: MiningService,
 | 
					    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 = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
 | 
				
			||||||
    this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
 | 
					    this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
    this.refreshMiningStats();
 | 
					    // When...
 | 
				
			||||||
    this.watchBlocks();
 | 
					    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 {
 | 
					  ngOnDestroy(): void {
 | 
				
			||||||
    this.blocksSubscription.unsubscribe();
 | 
					 | 
				
			||||||
    this.miningSubscription.unsubscribe();      
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  refreshMiningStats() {
 | 
					  generatePoolsChartSerieData(miningStats) {
 | 
				
			||||||
    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() {
 | 
					 | 
				
			||||||
    const poolShareThreshold = 0.5; // Do not draw pools which hashrate share is lower than that
 | 
					    const poolShareThreshold = 0.5; // Do not draw pools which hashrate share is lower than that
 | 
				
			||||||
    const data: object[] = [];
 | 
					    const data: object[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.miningStats.pools.forEach((pool) => {
 | 
					    miningStats.pools.forEach((pool) => {
 | 
				
			||||||
      if (parseFloat(pool.share) < poolShareThreshold) {
 | 
					      if (parseFloat(pool.share) < poolShareThreshold) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      data.push({
 | 
					      data.push({
 | 
				
			||||||
        value: pool.share,
 | 
					        value: pool.share,
 | 
				
			||||||
        name: pool.name,
 | 
					        name: pool.name + ` (${pool.share}%)`,
 | 
				
			||||||
        label: { color: '#FFFFFF' },
 | 
					        label: { color: '#FFFFFF' },
 | 
				
			||||||
        tooltip: {
 | 
					        tooltip: {
 | 
				
			||||||
          formatter: () => {
 | 
					          formatter: () => {
 | 
				
			||||||
@ -113,7 +109,7 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    return data;
 | 
					    return data;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  prepareChartOptions() {
 | 
					  prepareChartOptions(miningStats) {
 | 
				
			||||||
    this.chartOptions = {
 | 
					    this.chartOptions = {
 | 
				
			||||||
      title: {
 | 
					      title: {
 | 
				
			||||||
        text: (this.poolsWindowPreference === '1d') ? 'Hashrate distribution' : 'Block distribution',
 | 
					        text: (this.poolsWindowPreference === '1d') ? 'Hashrate distribution' : 'Block distribution',
 | 
				
			||||||
@ -143,7 +139,7 @@ export class PoolRankingComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
          name: 'Mining pool',
 | 
					          name: 'Mining pool',
 | 
				
			||||||
          type: 'pie',
 | 
					          type: 'pie',
 | 
				
			||||||
          radius: ['30%', '70%'],
 | 
					          radius: ['30%', '70%'],
 | 
				
			||||||
          data: this.generatePoolsChartSerieData(),
 | 
					          data: this.generatePoolsChartSerieData(miningStats),
 | 
				
			||||||
          labelLine: {
 | 
					          labelLine: {
 | 
				
			||||||
            lineStyle: {
 | 
					            lineStyle: {
 | 
				
			||||||
              width: 2,
 | 
					              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 ITranslators { [language: string]: string; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface SinglePoolStats {
 | 
					export interface SinglePoolStats {
 | 
				
			||||||
  pooldId: number,
 | 
					  pooldId: number;
 | 
				
			||||||
  name: string,
 | 
					  name: string;
 | 
				
			||||||
  link: string,
 | 
					  link: string;
 | 
				
			||||||
  blockCount: number,
 | 
					  blockCount: number;
 | 
				
			||||||
  emptyBlocks: number,
 | 
					  emptyBlocks: number;
 | 
				
			||||||
  rank: number,
 | 
					  rank: number;
 | 
				
			||||||
  share: string,
 | 
					  share: string;
 | 
				
			||||||
  lastEstimatedHashrate: string,
 | 
					  lastEstimatedHashrate: string;
 | 
				
			||||||
  emptyBlockRatio: string,
 | 
					  emptyBlockRatio: string;
 | 
				
			||||||
  logo: string,
 | 
					  logo: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface PoolsStats {
 | 
					export interface PoolsStats {
 | 
				
			||||||
  blockCount: number,
 | 
					  blockCount: number;
 | 
				
			||||||
  lastEstimatedHashrate: number,
 | 
					  lastEstimatedHashrate: number;
 | 
				
			||||||
  pools: SinglePoolStats[],
 | 
					  pools: SinglePoolStats[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ITranslators { [language: string]: string; }
 | 
					export interface ITranslators { [language: string]: string; }
 | 
				
			||||||
 | 
				
			|||||||
@ -6,17 +6,17 @@ import { ApiService } from '../services/api.service';
 | 
				
			|||||||
import { StateService } from './state.service';
 | 
					import { StateService } from './state.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface MiningUnits {
 | 
					export interface MiningUnits {
 | 
				
			||||||
  hashrateDivider: number,
 | 
					  hashrateDivider: number;
 | 
				
			||||||
  hashrateUnit: string,
 | 
					  hashrateUnit: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface MiningStats {
 | 
					export interface MiningStats {
 | 
				
			||||||
  lastEstimatedHashrate: string,
 | 
					  lastEstimatedHashrate: string;
 | 
				
			||||||
  blockCount: number,
 | 
					  blockCount: number;
 | 
				
			||||||
  totalEmptyBlock: number,
 | 
					  totalEmptyBlock: number;
 | 
				
			||||||
  totalEmptyBlockRatio: string,
 | 
					  totalEmptyBlockRatio: string;
 | 
				
			||||||
  pools: SinglePoolStats[],
 | 
					  pools: SinglePoolStats[];
 | 
				
			||||||
  miningUnits: MiningUnits,
 | 
					  miningUnits: MiningUnits;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Injectable({
 | 
					@Injectable({
 | 
				
			||||||
@ -38,15 +38,15 @@ export class MiningService {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Set the hashrate power of ten we want to display
 | 
					   * Set the hashrate power of ten we want to display
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  public getMiningUnits() : MiningUnits {
 | 
					  public getMiningUnits(): MiningUnits {
 | 
				
			||||||
    const powerTable = {
 | 
					    const powerTable = {
 | 
				
			||||||
      0: "H/s",
 | 
					      0: 'H/s',
 | 
				
			||||||
      3: "kH/s",
 | 
					      3: 'kH/s',
 | 
				
			||||||
      6: "MH/s",
 | 
					      6: 'MH/s',
 | 
				
			||||||
      9: "GH/s",
 | 
					      9: 'GH/s',
 | 
				
			||||||
      12: "TH/s",
 | 
					      12: 'TH/s',
 | 
				
			||||||
      15: "PH/s",
 | 
					      15: 'PH/s',
 | 
				
			||||||
      18: "EH/s",
 | 
					      18: 'EH/s',
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // I think it's fine to hardcode this since we don't have x1000 hashrate jump everyday
 | 
					    // 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 miningUnits = this.getMiningUnits();
 | 
				
			||||||
    const hashrateDivider = miningUnits.hashrateDivider;
 | 
					    const hashrateDivider = miningUnits.hashrateDivider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -77,7 +77,7 @@ export class MiningService {
 | 
				
			|||||||
        emptyBlockRatio: (poolStat.emptyBlocks / poolStat.blockCount * 100).toFixed(2),
 | 
					        emptyBlockRatio: (poolStat.emptyBlocks / poolStat.blockCount * 100).toFixed(2),
 | 
				
			||||||
        logo: `./resources/mining-pools/` + poolStat.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg',
 | 
					        logo: `./resources/mining-pools/` + poolStat.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg',
 | 
				
			||||||
        ...poolStat
 | 
					        ...poolStat
 | 
				
			||||||
      }
 | 
					      };
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user