Improve mining graphs timespan selection UX

This commit is contained in:
nymkappa 2022-04-11 18:17:36 +09:00
parent 848e02eca0
commit 7dd0173e84
No known key found for this signature in database
GPG Key ID: E155910B16E8BD04
13 changed files with 158 additions and 97 deletions

View File

@ -27,6 +27,7 @@ class Mining {
case '3m': timeRange = 7200; break; // 2h
case '1m': timeRange = 1800; break; // 30min
case '1w': timeRange = 300; break; // 5min
case '3d': timeRange = 1; break;
case '24h': timeRange = 1; break;
default: timeRange = 86400; break; // 24h
}

View File

@ -1,41 +1,43 @@
<div [class]="widget === false ? 'full-container' : ''">
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
<div class="full-container">
<div class="card-header mb-0 mb-md-4">
<span i18n="mining.block-fees">Block fees</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as hashrates">
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as stats">
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 1">
<input ngbButton type="radio" [value]="'24h'"> 24h
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1">
<input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 7">
<input ngbButton type="radio" [value]="'1w'"> 1W
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 3">
<input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 30">
<input ngbButton type="radio" [value]="'1m'"> 1M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 7">
<input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
<input ngbButton type="radio" [value]="'3m'"> 3M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 30">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 180">
<input ngbButton type="radio" [value]="'6m'"> 6M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 365">
<input ngbButton type="radio" [value]="'1y'"> 1Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 730">
<input ngbButton type="radio" [value]="'2y'"> 2Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'"> 3Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm">
<input ngbButton type="radio" [value]="'all'"> ALL
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label>
</div>
</form>
</div>
<div [class]="!widget ? 'chart' : 'chart-widget'" echarts [initOpts]="chartInitOptions" [options]="chartOptions">
<div class="chart" echarts [initOpts]="chartInitOptions" [options]="chartOptions">
</div>
<div class="text-center loadingGraphs" *ngIf="isLoading">
<div class="spinner-border text-light"></div>

View File

@ -7,6 +7,8 @@ import { SeoService } from 'src/app/services/seo.service';
import { formatNumber } from '@angular/common';
import { FormBuilder, FormGroup } from '@angular/forms';
import { formatterXAxisLabel } from 'src/app/shared/graphs.utils';
import { StorageService } from 'src/app/services/storage.service';
import { MiningService } from 'src/app/services/mining.service';
@Component({
selector: 'app-block-fees-graph',
@ -24,10 +26,10 @@ import { formatterXAxisLabel } from 'src/app/shared/graphs.utils';
})
export class BlockFeesGraphComponent implements OnInit {
@Input() tableOnly = false;
@Input() widget = false;
@Input() right: number | string = 45;
@Input() left: number | string = 75;
miningWindowPreference: string;
radioGroupForm: FormGroup;
chartOptions: EChartsOption = {};
@ -44,21 +46,25 @@ export class BlockFeesGraphComponent implements OnInit {
@Inject(LOCALE_ID) public locale: string,
private seoService: SeoService,
private apiService: ApiService,
private formBuilder: FormBuilder
private formBuilder: FormBuilder,
private storageService: StorageService,
private miningService: MiningService
) {
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
this.radioGroupForm.controls.dateSpan.setValue('1y');
}
ngOnInit(): void {
if (!this.widget) {
this.seoService.setTitle($localize`:@@mining.block-fees:Block Fees`);
}
this.seoService.setTitle($localize`:@@mining.block-fees:Block Fees`);
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
this.statsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
.pipe(
startWith('1y'),
startWith(this.miningWindowPreference),
switchMap((timespan) => {
this.storageService.setValue('miningWindowPreference', timespan);
this.timespan = timespan;
this.isLoading = true;
return this.apiService.getHistoricalBlockFees$(timespan)
@ -103,7 +109,7 @@ export class BlockFeesGraphComponent implements OnInit {
left: this.left,
},
tooltip: {
show: !this.isMobile() || !this.widget,
show: !this.isMobile(),
trigger: 'axis',
axisPointer: {
type: 'line'
@ -161,7 +167,7 @@ export class BlockFeesGraphComponent implements OnInit {
},
},
],
dataZoom: this.widget ? null : [{
dataZoom: [{
type: 'inside',
realtime: true,
zoomLock: true,

View File

@ -20,25 +20,28 @@
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
<span i18n="mining.hashrate-difficulty">Hashrate & Difficulty</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats">
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
<input ngbButton type="radio" [value]="'3m'"> 3M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 30">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 180">
<input ngbButton type="radio" [value]="'6m'"> 6M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 365">
<input ngbButton type="radio" [value]="'1y'"> 1Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 730">
<input ngbButton type="radio" [value]="'2y'"> 2Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'"> 3Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm">
<input ngbButton type="radio" [value]="'all'"> ALL
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label>
</div>
</form>

View File

@ -132,4 +132,4 @@
display: block;
max-width: 80px;
margin: 15px auto 3px;
}
}

View File

@ -7,6 +7,8 @@ import { SeoService } from 'src/app/services/seo.service';
import { formatNumber } from '@angular/common';
import { FormBuilder, FormGroup } from '@angular/forms';
import { selectPowerOfTen } from 'src/app/bitcoin.utils';
import { StorageService } from 'src/app/services/storage.service';
import { MiningService } from 'src/app/services/mining.service';
@Component({
selector: 'app-hashrate-chart',
@ -28,6 +30,7 @@ export class HashrateChartComponent implements OnInit {
@Input() right: number | string = 45;
@Input() left: number | string = 75;
miningWindowPreference: string;
radioGroupForm: FormGroup;
chartOptions: EChartsOption = {};
@ -47,20 +50,32 @@ export class HashrateChartComponent implements OnInit {
private apiService: ApiService,
private formBuilder: FormBuilder,
private cd: ChangeDetectorRef,
private storageService: StorageService,
private miningService: MiningService
) {
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
this.radioGroupForm.controls.dateSpan.setValue('1y');
}
ngOnInit(): void {
if (!this.widget) {
let firstRun = true;
if (this.widget) {
this.miningWindowPreference = '1y';
} else {
this.seoService.setTitle($localize`:@@mining.hashrate-difficulty:Hashrate and Difficulty`);
this.miningWindowPreference = this.miningService.getDefaultTimespan('1m');
}
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
this.hashrateObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
.pipe(
startWith('1y'),
startWith(this.miningWindowPreference),
switchMap((timespan) => {
if (!this.widget && !firstRun) {
this.storageService.setValue('miningWindowPreference', timespan);
}
firstRun = false;
this.miningWindowPreference = timespan;
this.isLoading = true;
return this.apiService.getHistoricalHashrate$(timespan)
.pipe(

View File

@ -1,32 +1,35 @@
<div [class]="widget === false ? 'full-container' : ''">
<div class="full-container">
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
<span *ngIf="!widget" i18n="mining.pools-dominance">Mining pools dominance</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
<div class="card-header mb-0 mb-md-4">
<span i18n="mining.pools-dominance">Mining pools dominance</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats">
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
<input ngbButton type="radio" [value]="'3m'"> 3M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 30">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 180">
<input ngbButton type="radio" [value]="'6m'"> 6M
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 365">
<input ngbButton type="radio" [value]="'1y'"> 1Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 730">
<input ngbButton type="radio" [value]="'2y'"> 2Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'"> 3Y
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm">
<input ngbButton type="radio" [value]="'all'"> ALL
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label>
</div>
</form>
</div>
<div [class]="!widget ? 'chart' : 'chart-widget'"
<div class="chart"
echarts [initOpts]="chartInitOptions" [options]="chartOptions"></div>
<div class="text-center loadingGraphs" *ngIf="isLoading">
<div class="spinner-border text-light"></div>

View File

@ -6,6 +6,8 @@ import { ApiService } from 'src/app/services/api.service';
import { SeoService } from 'src/app/services/seo.service';
import { FormBuilder, FormGroup } from '@angular/forms';
import { poolsColor } from 'src/app/app.constants';
import { StorageService } from 'src/app/services/storage.service';
import { MiningService } from 'src/app/services/mining.service';
@Component({
selector: 'app-hashrate-chart-pools',
@ -22,10 +24,10 @@ import { poolsColor } from 'src/app/app.constants';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HashrateChartPoolsComponent implements OnInit {
@Input() widget = false;
@Input() right: number | string = 45;
@Input() left: number | string = 25;
miningWindowPreference: string;
radioGroupForm: FormGroup;
chartOptions: EChartsOption = {};
@ -44,20 +46,29 @@ export class HashrateChartPoolsComponent implements OnInit {
private apiService: ApiService,
private formBuilder: FormBuilder,
private cd: ChangeDetectorRef,
private storageService: StorageService,
private miningService: MiningService
) {
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
this.radioGroupForm.controls.dateSpan.setValue('1y');
}
ngOnInit(): void {
if (!this.widget) {
this.seoService.setTitle($localize`:@@mining.pools-historical-dominance:Pools Historical Dominance`);
}
let firstRun = true;
this.seoService.setTitle($localize`:@@mining.pools-historical-dominance:Pools Historical Dominance`);
this.miningWindowPreference = this.miningService.getDefaultTimespan('1m');
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
this.hashrateObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
.pipe(
startWith('1y'),
startWith(this.miningWindowPreference),
switchMap((timespan) => {
if (!firstRun) {
this.storageService.setValue('miningWindowPreference', timespan);
}
firstRun = false;
this.isLoading = true;
return this.apiService.getHistoricalPoolsHashrate$(timespan)
.pipe(
@ -157,11 +168,11 @@ export class HashrateChartPoolsComponent implements OnInit {
grid: {
right: this.right,
left: this.left,
bottom: this.widget ? 30 : 70,
top: this.widget || this.isMobile() ? 10 : 50,
bottom: 70,
top: this.isMobile() ? 10 : 50,
},
tooltip: {
show: !this.isMobile() || !this.widget,
show: !this.isMobile(),
trigger: 'axis',
axisPointer: {
type: 'line'
@ -188,9 +199,9 @@ export class HashrateChartPoolsComponent implements OnInit {
},
xAxis: data.series.length === 0 ? undefined : {
type: 'time',
splitNumber: (this.isMobile() || this.widget) ? 5 : 10,
splitNumber: (this.isMobile()) ? 5 : 10,
},
legend: (this.isMobile() || this.widget || data.series.length === 0) ? undefined : {
legend: (this.isMobile() || data.series.length === 0) ? undefined : {
data: data.legends
},
yAxis: data.series.length === 0 ? undefined : {
@ -207,7 +218,7 @@ export class HashrateChartPoolsComponent implements OnInit {
min: 0,
},
series: data.series,
dataZoom: this.widget ? null : [{
dataZoom: [{
type: 'inside',
realtime: true,
zoomLock: true,

View File

@ -55,7 +55,7 @@
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 1095">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label>
<label ngbButtonLabel class="btn-primary btn-sm">
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay > 1095">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label>
</div>
@ -79,7 +79,7 @@
<th class="d-none d-md-block" i18n="mining.rank">Rank</th>
<th class=""></th>
<th class="" i18n="mining.pool-name">Pool</th>
<th class="" *ngIf="this.poolsWindowPreference === '24h'" i18n="mining.hashrate">Hashrate</th>
<th class="" *ngIf="this.miningWindowPreference === '24h'" i18n="mining.hashrate">Hashrate</th>
<th class="" i18n="master-page.blocks">Blocks</th>
<th class="d-none d-md-block" i18n="mining.empty-blocks">Empty Blocks</th>
</tr>
@ -90,7 +90,7 @@
<td class="text-right"><img width="25" height="25" src="{{ pool.logo }}"
onError="this.src = './resources/mining-pools/default.svg'"></td>
<td class=""><a [routerLink]="[('/mining/pool/' + pool.slug) | relativeUrl]">{{ pool.name }}</a></td>
<td class="" *ngIf="this.poolsWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{
<td class="" *ngIf="this.miningWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{
miningStats.miningUnits.hashrateUnit }}</td>
<td class="">{{ pool['blockText'] }}</td>
<td class="d-none d-md-block">{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%)</td>
@ -99,7 +99,7 @@
<td class="d-none d-md-block"></td>
<td class="text-right"></td>
<td class="" i18n="mining.all-miners"><b>All miners</b></td>
<td class="" *ngIf="this.poolsWindowPreference === '24h'"><b>{{ miningStats.lastEstimatedHashrate}} {{
<td class="" *ngIf="this.miningWindowPreference === '24h'"><b>{{ miningStats.lastEstimatedHashrate}} {{
miningStats.miningUnits.hashrateUnit }}</b></td>
<td class=""><b>{{ miningStats.blockCount }}</b></td>
<td class="d-none d-md-block"><b>{{ miningStats.totalEmptyBlock }} ({{ miningStats.totalEmptyBlockRatio

View File

@ -19,9 +19,9 @@ import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PoolRankingComponent implements OnInit {
@Input() widget: boolean = false;
@Input() widget = false;
poolsWindowPreference: string;
miningWindowPreference: string;
radioGroupForm: FormGroup;
isLoading = true;
@ -48,13 +48,13 @@ export class PoolRankingComponent implements OnInit {
ngOnInit(): void {
if (this.widget) {
this.poolsWindowPreference = '1w';
this.miningWindowPreference = '1w';
} else {
this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
}
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
// When...
this.miningStatsObservable$ = combineLatest([
@ -67,12 +67,12 @@ export class PoolRankingComponent implements OnInit {
// ...or we change the timespan
this.radioGroupForm.get('dateSpan').valueChanges
.pipe(
startWith(this.poolsWindowPreference), // (trigger when the page loads)
startWith(this.miningWindowPreference), // (trigger when the page loads)
tap((value) => {
if (!this.widget) {
this.storageService.setValue('poolsWindowPreference', value);
this.storageService.setValue('miningWindowPreference', value);
}
this.poolsWindowPreference = value;
this.miningWindowPreference = value;
})
)
])
@ -80,7 +80,7 @@ export class PoolRankingComponent implements OnInit {
.pipe(
switchMap(() => {
this.isLoading = true;
return this.miningService.getMiningStats(this.poolsWindowPreference)
return this.miningService.getMiningStats(this.miningWindowPreference)
.pipe(
catchError((e) => of(this.getEmptyMiningStat()))
);
@ -150,7 +150,7 @@ export class PoolRankingComponent implements OnInit {
},
borderColor: '#000',
formatter: () => {
if (this.poolsWindowPreference === '24h') {
if (this.miningWindowPreference === '24h') {
return `<b style="color: white">${pool.name} (${pool.share}%)</b><br>` +
pool.lastEstimatedHashrate.toString() + ' PH/s' +
`<br>` + pool.blockCount.toString() + ` blocks`;
@ -186,7 +186,7 @@ export class PoolRankingComponent implements OnInit {
},
borderColor: '#000',
formatter: () => {
if (this.poolsWindowPreference === '24h') {
if (this.miningWindowPreference === '24h') {
return `<b style="color: white">${'Other'} (${totalShareOther.toFixed(2)}%)</b><br>` +
totalEstimatedHashrateOther.toString() + ' PH/s' +
`<br>` + totalBlockOther.toString() + ` blocks`;

View File

@ -4,6 +4,7 @@ import { map } from 'rxjs/operators';
import { PoolsStats, SinglePoolStats } from '../interfaces/node-api.interface';
import { ApiService } from '../services/api.service';
import { StateService } from './state.service';
import { StorageService } from './storage.service';
export interface MiningUnits {
hashrateDivider: number;
@ -28,8 +29,12 @@ export class MiningService {
constructor(
private stateService: StateService,
private apiService: ApiService,
private storageService: StorageService,
) { }
/**
* Generate pool ranking stats
*/
public getMiningStats(interval: string): Observable<MiningStats> {
return this.apiService.listPools$(interval).pipe(
map(pools => this.generateMiningStats(pools))
@ -63,6 +68,20 @@ export class MiningService {
};
}
/**
* Get the default selection timespan, cap with `min`
*/
public getDefaultTimespan(min: string): string {
const timespans = [
'24h', '3d', '1w', '1m', '3m', '6m', '1y', '2y', '3y', 'all'
];
const preference = this.storageService.getValue('miningWindowPreference') ?? '1w';
if (timespans.indexOf(preference) < timespans.indexOf(min)) {
return min;
}
return preference;
}
private generateMiningStats(stats: PoolsStats): MiningStats {
const miningUnits = this.getMiningUnits();
const hashrateDivider = miningUnits.hashrateDivider;

View File

@ -7,21 +7,21 @@ import { Router, ActivatedRoute } from '@angular/router';
export class StorageService {
constructor(private router: Router, private route: ActivatedRoute) {
this.setDefaultValueIfNeeded('graphWindowPreference', '2h');
this.setDefaultValueIfNeeded('poolsWindowPreference', '1w');
this.setDefaultValueIfNeeded('miningWindowPreference', '1w');
}
setDefaultValueIfNeeded(key: string, defaultValue: string) {
let graphWindowPreference: string = this.getValue(key);
const graphWindowPreference: string = this.getValue(key);
if (graphWindowPreference === null) { // First visit to mempool.space
if (this.router.url.includes('graphs') && key === 'graphWindowPreference' ||
this.router.url.includes('pools') && key === 'poolsWindowPreference'
this.router.url.includes('pools') && key === 'miningWindowPreference'
) {
this.setValue(key, this.route.snapshot.fragment ? this.route.snapshot.fragment : defaultValue);
} else {
this.setValue(key, defaultValue);
}
} else if (this.router.url.includes('graphs') && key === 'graphWindowPreference' ||
this.router.url.includes('pools') && key === 'poolsWindowPreference'
this.router.url.includes('pools') && key === 'miningWindowPreference'
) {
// Visit a different graphs#fragment from last visit
if (this.route.snapshot.fragment !== null && graphWindowPreference !== this.route.snapshot.fragment) {

View File

@ -38,6 +38,7 @@ do for url in / \
'/api/v1/mining/reward-stats/144' \
'/api/v1/mining/blocks-extras' \
'/api/v1/mining/blocks/fees/24h' \
'/api/v1/mining/blocks/fees/3d' \
'/api/v1/mining/blocks/fees/1w' \
'/api/v1/mining/blocks/fees/1m' \
'/api/v1/mining/blocks/fees/3m' \