diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html index 3698a3060..faf48eac7 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html @@ -23,6 +23,9 @@ + diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts index de1202193..3a8107634 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnDestroy, OnInit } from '@angular/core'; -import { EChartsOption, graphic } from 'echarts'; +import { EChartsOption } from 'echarts'; import { Observable, Subscription, combineLatest, fromEvent } from 'rxjs'; -import { map, max, startWith, switchMap, tap } from 'rxjs/operators'; +import { startWith, switchMap, tap } from 'rxjs/operators'; import { SeoService } from '../../../services/seo.service'; import { formatNumber } from '@angular/common'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; @@ -11,7 +11,6 @@ import { MiningService } from '../../../services/mining.service'; import { ActivatedRoute } from '@angular/router'; import { Acceleration } from '../../../interfaces/node-api.interface'; import { ServicesApiServices } from '../../../services/services-api.service'; -import { ApiService } from '../../../services/api.service'; @Component({ selector: 'app-acceleration-fees-graph', @@ -55,7 +54,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { constructor( @Inject(LOCALE_ID) public locale: string, private seoService: SeoService, - private apiService: ApiService, private servicesApiService: ServicesApiServices, private formBuilder: UntypedFormBuilder, private storageService: StorageService, @@ -69,104 +67,56 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.isLoading = true; if (this.widget) { - this.miningWindowPreference = '1m'; - this.timespan = this.miningWindowPreference; - - this.statsObservable$ = combineLatest([ - (this.accelerations$ || this.servicesApiService.getAccelerationHistory$({ timeframe: this.miningWindowPreference })), - this.apiService.getHistoricalBlockFees$(this.miningWindowPreference), - fromEvent(window, 'resize').pipe(startWith(null)), - ]).pipe( - tap(([accelerations, blockFeesResponse]) => { - this.prepareChartOptions(accelerations, blockFeesResponse.body); - }), - map(([accelerations, blockFeesResponse]) => { - return { - avgFeesPaid: accelerations.filter(acc => acc.status === 'completed').reduce((total, acc) => total + (acc.feePaid - acc.baseFee - acc.vsizeFee), 0) / accelerations.length - }; - }), - ); + this.miningWindowPreference = '3m'; } else { this.seoService.setTitle($localize`:@@bcf34abc2d9ed8f45a2f65dd464c46694e9a181e:Acceleration Fees`); - this.miningWindowPreference = this.miningService.getDefaultTimespan('1w'); - this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); - this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); - this.route.fragment.subscribe((fragment) => { - if (['24h', '3d', '1w', '1m'].indexOf(fragment) > -1) { - this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); - } - }); - this.statsObservable$ = combineLatest([ - this.radioGroupForm.get('dateSpan').valueChanges.pipe( - startWith(this.radioGroupForm.controls.dateSpan.value), - switchMap((timespan) => { - this.isLoading = true; - this.storageService.setValue('miningWindowPreference', timespan); - this.timespan = timespan; - return this.servicesApiService.getAccelerationHistory$({}); - }) - ), - this.radioGroupForm.get('dateSpan').valueChanges.pipe( - startWith(this.radioGroupForm.controls.dateSpan.value), - switchMap((timespan) => { - return this.apiService.getHistoricalBlockFees$(timespan); - }) - ) - ]).pipe( - tap(([accelerations, blockFeesResponse]) => { - this.prepareChartOptions(accelerations, blockFeesResponse.body); - }) - ); + this.miningWindowPreference = this.miningService.getDefaultTimespan('3m'); } - this.statsSubscription = this.statsObservable$.subscribe(() => { - this.isLoading = false; - this.cd.markForCheck(); + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route.fragment.subscribe((fragment) => { + if (['24h', '3d', '1w', '1m', '3m'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } }); + this.statsObservable$ = combineLatest([ + this.radioGroupForm.get('dateSpan').valueChanges.pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + switchMap((timespan) => { + if (!this.widget) { + this.storageService.setValue('miningWindowPreference', timespan); + } + this.isLoading = true; + this.timespan = timespan; + return this.servicesApiService.getAggregatedAccelerationHistory$({timeframe: this.timespan}); + }) + ), + fromEvent(window, 'resize').pipe(startWith(null)), + ]).pipe( + tap(([history]) => { + this.isLoading = false; + this.prepareChartOptions(history); + this.cd.markForCheck(); + }) + ); + + this.statsObservable$.subscribe(); } - prepareChartOptions(accelerations, blockFees) { + prepareChartOptions(data) { let title: object; - - const blockAccelerations = {}; - - for (const acceleration of accelerations) { - if (acceleration.status === 'completed') { - if (!blockAccelerations[acceleration.blockHeight]) { - blockAccelerations[acceleration.blockHeight] = []; - } - blockAccelerations[acceleration.blockHeight].push(acceleration); - } - } - - let last = null; - let minValue = Infinity; - let maxValue = 0; - const data = []; - for (const val of blockFees) { - if (last == null) { - last = val.avgHeight; - } - let totalFeeDelta = 0; - let totalFeePaid = 0; - let totalCount = 0; - let blockCount = 0; - while (last <= val.avgHeight) { - blockCount++; - totalFeeDelta += (blockAccelerations[last] || []).reduce((total, acc) => total + acc.feeDelta, 0); - totalFeePaid += (blockAccelerations[last] || []).reduce((total, acc) => total + (acc.feePaid - acc.baseFee - acc.vsizeFee), 0); - totalCount += (blockAccelerations[last] || []).length; - last++; - } - minValue = Math.min(minValue, val.avgFees); - maxValue = Math.max(maxValue, val.avgFees); - data.push({ - ...val, - feeDelta: totalFeeDelta, - avgFeePaid: (totalFeePaid / blockCount), - accelerations: totalCount / blockCount, - }); + if (data.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`No accelerated transaction for this timeframe`, + left: 'center', + top: 'center' + }; } this.chartOptions = { @@ -197,29 +147,23 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { align: 'left', }, borderColor: '#000', - formatter: function (data) { - if (data.length <= 0) { - return ''; - } - let tooltip = ` - ${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}
`; + formatter: (ticks) => { + let tooltip = `${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10) * 1000)}
`; - for (const tick of data.reverse()) { - if (tick.data[1] >= 1_000_000) { - tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1] / 100_000_000, this.locale, '1.0-3')} BTC
`; - } else { - tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')} sats
`; - } + if (ticks[0].data[1] > 10_000_000) { + tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1] / 100_000_000, this.locale, '1.0-0')} BTC
`; + } else { + tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1], this.locale, '1.0-0')} sats
`; } if (['24h', '3d'].includes(this.timespan)) { - tooltip += `` + $localize`At block: ${data[0].data[2]}` + ``; + tooltip += `` + $localize`At block: ${ticks[0].data[2]}` + ``; } else { - tooltip += `` + $localize`Around block: ${data[0].data[2]}` + ``; + tooltip += `` + $localize`Around block: ${ticks[0].data[2]}` + ``; } return tooltip; - }.bind(this) + } }, xAxis: data.length === 0 ? undefined : { @@ -243,15 +187,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { legend: { data: [ { - name: 'In-band fees per block', - inactiveColor: 'rgb(110, 112, 121)', - textStyle: { - color: 'white', - }, - icon: 'roundRect', - }, - { - name: 'Total bid boost per block', + name: 'Total bid boost', inactiveColor: 'rgb(110, 112, 121)', textStyle: { color: 'white', @@ -260,8 +196,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { }, ], selected: { - 'In-band fees per block': false, - 'Total bid boost per block': true, + 'Total bid boost': true, }, show: !this.widget, }, @@ -304,21 +239,13 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { { legendHoverLink: false, zlevel: 1, - name: 'Total bid boost per block', - data: data.map(block => [block.timestamp * 1000, block.avgFeePaid, block.avgHeight]), + name: 'Total bid boost', + data: data.map(h => { + return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight] + }), stack: 'Total', type: 'bar', - barWidth: '100%', - large: true, - }, - { - legendHoverLink: false, - zlevel: 0, - name: 'In-band fees per block', - data: data.map(block => [block.timestamp * 1000, block.avgFees, block.avgHeight]), - stack: 'Total', - type: 'bar', - barWidth: '100%', + barWidth: '90%', large: true, }, ], @@ -347,17 +274,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { } }, }], - visualMap: { - type: 'continuous', - min: minValue, - max: maxValue, - dimension: 1, - seriesIndex: 1, - show: false, - inRange: { - color: ['#F4511E7f', '#FB8C007f', '#FFB3007f', '#FDD8357f', '#7CB3427f'].reverse() // Gradient color range - } - }, }; } diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html index 0afae6e7b..5e049198a 100644 --- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html @@ -22,12 +22,12 @@
Acceleration stats  - (1 month) + (3 months)
- +
@@ -59,7 +59,6 @@ [height]="graphHeight" [attr.data-cy]="'acceleration-fees'" [widget]=true - [accelerations$]="accelerations$" >
View more »
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts index 04fa2a4cd..ba9240d1b 100644 --- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts @@ -60,7 +60,7 @@ export class AcceleratorDashboardComponent implements OnInit { this.accelerations$ = this.stateService.chainTip$.pipe( distinctUntilChanged(), switchMap(() => { - return this.serviceApiServices.getAccelerationHistory$({ timeframe: '1m', page: 1, pageLength: 100}).pipe( + return this.serviceApiServices.getAccelerationHistory$({ timeframe: '3m', page: 1, pageLength: 100}).pipe( catchError(() => { return of([]); }), diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts index 5ec1e4240..f41c5b42c 100644 --- a/frontend/src/app/services/services-api.service.ts +++ b/frontend/src/app/services/services-api.service.ts @@ -145,6 +145,10 @@ export class ServicesApiServices { return this.httpClient.get(`${SERVICES_API_PREFIX}/accelerator/accelerations`); } + getAggregatedAccelerationHistory$(params: AccelerationHistoryParams): Observable { + return this.httpClient.get(`${SERVICES_API_PREFIX}/accelerator/accelerations/history/aggregated`, { params: { ...params } }); + } + getAccelerationHistory$(params: AccelerationHistoryParams): Observable { return this.httpClient.get(`${SERVICES_API_PREFIX}/accelerator/accelerations/history`, { params: { ...params } }); }