mirror of
https://github.com/mempool/mempool.git
synced 2026-08-13 12:33:11 +02:00
[graph] add price chart in available graphs
This commit is contained in:
parent
968080ca26
commit
31431d3a11
3 changed files with 47 additions and 39 deletions
|
|
@ -1,4 +1,4 @@
|
|||
<div *ngIf="stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING || stateService.env.ACCELERATOR" class="mb-3 d-flex menu" [style]="{'flex-wrap': flexWrap ? 'wrap' : ''}">
|
||||
<div *ngIf="stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING || stateService.env.ACCELERATOR || (stateService.env.HISTORICAL_PRICE && isMainnet)" class="mb-3 d-flex menu" [style]="{'flex-wrap': flexWrap ? 'wrap' : ''}">
|
||||
|
||||
<a routerLinkActive="active" class="btn btn-primary w-33"
|
||||
[routerLink]="['/graphs/mempool' | relativeUrl]">Mempool</a>
|
||||
|
|
@ -52,6 +52,12 @@
|
|||
i18n="accelerator.acceleration-fees">Acceleration Fees</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (stateService.env.HISTORICAL_PRICE && isMainnet) {
|
||||
<a routerLinkActive="active" class="btn btn-primary w-33"
|
||||
[routerLink]="['/graphs/price' | relativeUrl]" i18n="price">Price</a>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div [class]="widget === false ? 'full-container' : ''">
|
||||
|
||||
<div *ngIf="widget">
|
||||
<div class="pool-distribution" *ngIf="(statsObservable$ | async) as stats; else loadingStats">
|
||||
<div class="pool-distribution" *ngIf="(pricesObservable$ | async) as stats; else loadingStats">
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="price-chart.bitcoin-price">Bitcoin Price</h5>
|
||||
<p class="card-text">
|
||||
|
|
@ -27,24 +27,24 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as stats">
|
||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="pricesObservable$ | async">
|
||||
<div class="btn-group btn-group-toggle" name="radioBasic">
|
||||
<label class="btn btn-primary btn-sm" *ngIf="stats.blockCount >= 4320" [class.active]="radioGroupForm.get('dateSpan').value === '1m'">
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '1m'">
|
||||
<input type="radio" [value]="'1m'" fragment="1m" [routerLink]="['/graphs/price' | relativeUrl]" formControlName="dateSpan"> 1M
|
||||
</label>
|
||||
<label class="btn btn-primary btn-sm" *ngIf="stats.blockCount >= 12960" [class.active]="radioGroupForm.get('dateSpan').value === '3m'">
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '3m'">
|
||||
<input type="radio" [value]="'3m'" fragment="3m" [routerLink]="['/graphs/price' | relativeUrl]" formControlName="dateSpan"> 3M
|
||||
</label>
|
||||
<label class="btn btn-primary btn-sm" *ngIf="stats.blockCount >= 25920" [class.active]="radioGroupForm.get('dateSpan').value === '6m'">
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '6m'">
|
||||
<input type="radio" [value]="'6m'" fragment="6m" [routerLink]="['/graphs/price' | relativeUrl]" formControlName="dateSpan"> 6M
|
||||
</label>
|
||||
<label class="btn btn-primary btn-sm" *ngIf="stats.blockCount >= 52560" [class.active]="radioGroupForm.get('dateSpan').value === '1y'">
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '1y'">
|
||||
<input type="radio" [value]="'1y'" fragment="1y" [routerLink]="['/graphs/price' | relativeUrl]" formControlName="dateSpan"> 1Y
|
||||
</label>
|
||||
<label class="btn btn-primary btn-sm" *ngIf="stats.blockCount >= 105120" [class.active]="radioGroupForm.get('dateSpan').value === '2y'">
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '2y'">
|
||||
<input type="radio" [value]="'2y'" fragment="2y" [routerLink]="['/graphs/price' | relativeUrl]" formControlName="dateSpan"> 2Y
|
||||
</label>
|
||||
<label class="btn btn-primary btn-sm" *ngIf="stats.blockCount >= 157680" [class.active]="radioGroupForm.get('dateSpan').value === '3y'">
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '3y'">
|
||||
<input type="radio" [value]="'3y'" fragment="3y" [routerLink]="['/graphs/price' | relativeUrl]" formControlName="dateSpan"> 3Y
|
||||
</label>
|
||||
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === 'all'">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
|
||||
import { echarts, EChartsOption } from '@app/graphs/echarts';
|
||||
import { Observable } from 'rxjs';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
|
||||
import { ApiService } from '@app/services/api.service';
|
||||
import { SeoService } from '@app/services/seo.service';
|
||||
|
|
@ -45,7 +45,7 @@ export class PriceChartComponent implements OnInit {
|
|||
renderer: 'svg',
|
||||
};
|
||||
|
||||
statsObservable$: Observable<any>;
|
||||
pricesObservable$: Observable<any>;
|
||||
isLoading = true;
|
||||
formatNumber = formatNumber;
|
||||
chartInstance: any = undefined;
|
||||
|
|
@ -89,32 +89,48 @@ export class PriceChartComponent implements OnInit {
|
|||
}
|
||||
});
|
||||
|
||||
this.statsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
|
||||
.pipe(
|
||||
startWith(this.radioGroupForm.controls.dateSpan.value),
|
||||
switchMap((timespan) => {
|
||||
this.pricesObservable$ = combineLatest([
|
||||
this.radioGroupForm.get('dateSpan').valueChanges.pipe(startWith(this.radioGroupForm.controls.dateSpan.value)),
|
||||
this.stateService.fiatCurrency$,
|
||||
]).pipe(
|
||||
switchMap(([timespan, currency]) => {
|
||||
this.currency = currency;
|
||||
const now = new Date();
|
||||
let startTimestamp = 0;
|
||||
if (timespan === '1m') {
|
||||
startTimestamp = Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 1, now.getUTCDate());
|
||||
} else if (timespan === '3m') {
|
||||
startTimestamp = Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 3, now.getUTCDate());
|
||||
} else if (timespan === '6m') {
|
||||
startTimestamp = Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 6, now.getUTCDate());
|
||||
} else if (timespan === '1y') {
|
||||
startTimestamp = Date.UTC(now.getUTCFullYear() - 1, now.getUTCMonth(), now.getUTCDate());
|
||||
} else if (timespan === '2y') {
|
||||
startTimestamp = Date.UTC(now.getUTCFullYear() - 2, now.getUTCMonth(), now.getUTCDate());
|
||||
} else if (timespan === '3y') {
|
||||
startTimestamp = Date.UTC(now.getUTCFullYear() - 3, now.getUTCMonth(), now.getUTCDate());
|
||||
} // 'all' keeps startTimestamp = 0
|
||||
|
||||
this.isLoading = true;
|
||||
if (!this.widget) {
|
||||
this.storageService.setValue('miningWindowPreference', timespan);
|
||||
}
|
||||
this.currentTimespan = timespan;
|
||||
this.isLoading = true;
|
||||
return this.apiService.getHistoricalBlockFees$(timespan)
|
||||
return this.apiService.getHistoricalPrice$(undefined, this.currency)
|
||||
.pipe(
|
||||
tap((response) => {
|
||||
tap((response: any) => {
|
||||
this.prepareChartOptions({
|
||||
priceData: response.body.filter(val => val[this.currency] > 0).map(val => [val.timestamp * 1000, val[this.currency], val.avgHeight]),
|
||||
priceData: response.prices.filter((p: any) => p[this.currency] > 0 && p.time * 1000 >= startTimestamp).map((p: any) => [p.time * 1000, p[this.currency]]),
|
||||
});
|
||||
this.isLoading = false;
|
||||
}),
|
||||
map((response) => {
|
||||
const priceData = response.body.filter(val => val[this.currency] > 0);
|
||||
const latestPrice = priceData.length > 0 ? priceData[priceData.length - 1][this.currency] : null;
|
||||
const firstPrice = priceData.length > 0 ? priceData[0][this.currency] : null;
|
||||
map((response: any) => {
|
||||
const priceData = response.prices.filter((p: any) => p[this.currency] > 0 && p.time * 1000 >= startTimestamp).map((p: any) => p[this.currency]);
|
||||
const latestPrice = priceData.length > 0 ? priceData[0] : null;
|
||||
const firstPrice = priceData.length > 0 ? priceData[priceData.length - 1] : null;
|
||||
const percentChange = (latestPrice && firstPrice) ? ((latestPrice - firstPrice) / firstPrice) * 100 : 0;
|
||||
|
||||
return {
|
||||
blockCount: parseInt(response.headers.get('x-total-count'), 10),
|
||||
latestPrice: latestPrice,
|
||||
percentChange: percentChange,
|
||||
};
|
||||
|
|
@ -179,8 +195,6 @@ export class PriceChartComponent implements OnInit {
|
|||
for (const tick of data) {
|
||||
tooltip += `${tick.marker} ${tick.seriesName}: ${this.fiatCurrencyPipe.transform(tick.data[1], null, this.currency)}<br>`;
|
||||
}
|
||||
|
||||
tooltip += `<small>* On average around block ${data[0].data[2]}</small>`;
|
||||
return tooltip;
|
||||
}.bind(this)
|
||||
},
|
||||
|
|
@ -192,18 +206,6 @@ export class PriceChartComponent implements OnInit {
|
|||
hideOverlap: true,
|
||||
}
|
||||
},
|
||||
// legend: data.priceData.length === 0 ? undefined : {
|
||||
// data: [
|
||||
// {
|
||||
// name: 'BTC Price (' + this.currency + ')',
|
||||
// inactiveColor: 'rgb(110, 112, 121)',
|
||||
// textStyle: {
|
||||
// color: 'white',
|
||||
// },
|
||||
// icon: 'roundRect',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
yAxis: data.priceData.length === 0 ? undefined : [
|
||||
{
|
||||
type: 'value',
|
||||
|
|
@ -228,7 +230,7 @@ export class PriceChartComponent implements OnInit {
|
|||
// legendHoverLink: false,
|
||||
zlevel: 0,
|
||||
yAxisIndex: 0,
|
||||
name: 'BTC Price (' + this.currency + ')',
|
||||
name: `BTC${this.currency}`,
|
||||
data: data.priceData,
|
||||
type: 'line',
|
||||
smooth: 0.25,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue