[accelerator] show 3m stats, fix accel fee chart
This commit is contained in:
		
							parent
							
								
									cda5448f13
								
							
						
					
					
						commit
						8bd939b374
					
				| @ -23,6 +23,9 @@ | |||||||
|         <label class="btn btn-primary btn-sm" [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/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 1M |           <input type="radio" [value]="'1m'" fragment="1m" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 1M | ||||||
|         </label> |         </label> | ||||||
|  |         <label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '3m'"> | ||||||
|  |           <input type="radio" [value]="'3m'" fragment="3m" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 3M | ||||||
|  |         </label> | ||||||
|       </div> |       </div> | ||||||
|     </form> |     </form> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnDestroy, OnInit } from '@angular/core'; | 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 { 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 { SeoService } from '../../../services/seo.service'; | ||||||
| import { formatNumber } from '@angular/common'; | import { formatNumber } from '@angular/common'; | ||||||
| import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; | import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; | ||||||
| @ -11,7 +11,6 @@ import { MiningService } from '../../../services/mining.service'; | |||||||
| import { ActivatedRoute } from '@angular/router'; | import { ActivatedRoute } from '@angular/router'; | ||||||
| import { Acceleration } from '../../../interfaces/node-api.interface'; | import { Acceleration } from '../../../interfaces/node-api.interface'; | ||||||
| import { ServicesApiServices } from '../../../services/services-api.service'; | import { ServicesApiServices } from '../../../services/services-api.service'; | ||||||
| import { ApiService } from '../../../services/api.service'; |  | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-acceleration-fees-graph', |   selector: 'app-acceleration-fees-graph', | ||||||
| @ -55,7 +54,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|   constructor( |   constructor( | ||||||
|     @Inject(LOCALE_ID) public locale: string, |     @Inject(LOCALE_ID) public locale: string, | ||||||
|     private seoService: SeoService, |     private seoService: SeoService, | ||||||
|     private apiService: ApiService, |  | ||||||
|     private servicesApiService: ServicesApiServices, |     private servicesApiService: ServicesApiServices, | ||||||
|     private formBuilder: UntypedFormBuilder, |     private formBuilder: UntypedFormBuilder, | ||||||
|     private storageService: StorageService, |     private storageService: StorageService, | ||||||
| @ -69,32 +67,17 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
|     this.isLoading = true; |  | ||||||
|     if (this.widget) { |     if (this.widget) { | ||||||
|       this.miningWindowPreference = '1m'; |       this.miningWindowPreference = '3m'; | ||||||
|       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 |  | ||||||
|           }; |  | ||||||
|         }), |  | ||||||
|       ); |  | ||||||
|     } else { |     } else { | ||||||
|       this.seoService.setTitle($localize`:@@bcf34abc2d9ed8f45a2f65dd464c46694e9a181e:Acceleration Fees`); |       this.seoService.setTitle($localize`:@@bcf34abc2d9ed8f45a2f65dd464c46694e9a181e:Acceleration Fees`); | ||||||
|       this.miningWindowPreference = this.miningService.getDefaultTimespan('1w'); |       this.miningWindowPreference = this.miningService.getDefaultTimespan('3m'); | ||||||
|  |     } | ||||||
|     this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); |     this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); | ||||||
|     this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); |     this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); | ||||||
|  |      | ||||||
|     this.route.fragment.subscribe((fragment) => { |     this.route.fragment.subscribe((fragment) => { | ||||||
|         if (['24h', '3d', '1w', '1m'].indexOf(fragment) > -1) { |       if (['24h', '3d', '1w', '1m', '3m'].indexOf(fragment) > -1) { | ||||||
|         this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); |         this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @ -102,71 +85,38 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|       this.radioGroupForm.get('dateSpan').valueChanges.pipe( |       this.radioGroupForm.get('dateSpan').valueChanges.pipe( | ||||||
|         startWith(this.radioGroupForm.controls.dateSpan.value), |         startWith(this.radioGroupForm.controls.dateSpan.value), | ||||||
|         switchMap((timespan) => { |         switchMap((timespan) => { | ||||||
|             this.isLoading = true; |           if (!this.widget) { | ||||||
|             this.storageService.setValue('miningWindowPreference', timespan); |             this.storageService.setValue('miningWindowPreference', timespan); | ||||||
|  |           } | ||||||
|  |           this.isLoading = true; | ||||||
|           this.timespan = timespan; |           this.timespan = timespan; | ||||||
|             return this.servicesApiService.getAccelerationHistory$({}); |           return this.servicesApiService.getAggregatedAccelerationHistory$({timeframe: this.timespan}); | ||||||
|         }) |         }) | ||||||
|       ), |       ), | ||||||
|         this.radioGroupForm.get('dateSpan').valueChanges.pipe( |       fromEvent(window, 'resize').pipe(startWith(null)), | ||||||
|           startWith(this.radioGroupForm.controls.dateSpan.value), |  | ||||||
|           switchMap((timespan) => { |  | ||||||
|             return this.apiService.getHistoricalBlockFees$(timespan); |  | ||||||
|           }) |  | ||||||
|         ) |  | ||||||
|     ]).pipe( |     ]).pipe( | ||||||
|         tap(([accelerations, blockFeesResponse]) => { |       tap(([history]) => { | ||||||
|           this.prepareChartOptions(accelerations, blockFeesResponse.body); |         this.isLoading = false; | ||||||
|  |         this.prepareChartOptions(history); | ||||||
|  |         this.cd.markForCheck(); | ||||||
|       }) |       }) | ||||||
|     ); |     ); | ||||||
|     } | 
 | ||||||
|     this.statsSubscription = this.statsObservable$.subscribe(() => { |     this.statsObservable$.subscribe(); | ||||||
|       this.isLoading = false; |  | ||||||
|       this.cd.markForCheck(); |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   prepareChartOptions(accelerations, blockFees) { |   prepareChartOptions(data) { | ||||||
|     let title: object; |     let title: object; | ||||||
| 
 |     if (data.length === 0) { | ||||||
|     const blockAccelerations = {}; |       title = { | ||||||
| 
 |         textStyle: { | ||||||
|     for (const acceleration of accelerations) { |           color: 'grey', | ||||||
|       if (acceleration.status === 'completed') { |           fontSize: 15 | ||||||
|         if (!blockAccelerations[acceleration.blockHeight]) { |         }, | ||||||
|           blockAccelerations[acceleration.blockHeight] = []; |         text: $localize`No accelerated transaction for this timeframe`, | ||||||
|         } |         left: 'center', | ||||||
|         blockAccelerations[acceleration.blockHeight].push(acceleration); |         top: 'center' | ||||||
|       } |       }; | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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, |  | ||||||
|       }); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.chartOptions = { |     this.chartOptions = { | ||||||
| @ -197,29 +147,23 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|           align: 'left', |           align: 'left', | ||||||
|         }, |         }, | ||||||
|         borderColor: '#000', |         borderColor: '#000', | ||||||
|         formatter: function (data) { |         formatter: (ticks) => { | ||||||
|           if (data.length <= 0) { |           let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10) * 1000)}</b><br>`; | ||||||
|             return ''; |  | ||||||
|           } |  | ||||||
|           let tooltip = `<b style="color: white; margin-left: 2px">
 |  | ||||||
|             ${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}</b><br>`;
 |  | ||||||
| 
 | 
 | ||||||
|           for (const tick of data.reverse()) { |           if (ticks[0].data[1] > 10_000_000) { | ||||||
|             if (tick.data[1] >= 1_000_000) { |             tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1] / 100_000_000, this.locale, '1.0-0')} BTC<br>`; | ||||||
|               tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1] / 100_000_000, this.locale, '1.0-3')} BTC<br>`; |  | ||||||
|           } else { |           } else { | ||||||
|               tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')} sats<br>`; |             tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1], this.locale, '1.0-0')} sats<br>`; | ||||||
|             } |  | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if (['24h', '3d'].includes(this.timespan)) { |           if (['24h', '3d'].includes(this.timespan)) { | ||||||
|             tooltip += `<small>` + $localize`At block: ${data[0].data[2]}` + `</small>`; |             tooltip += `<small>` + $localize`At block: ${ticks[0].data[2]}` + `</small>`; | ||||||
|           } else { |           } else { | ||||||
|             tooltip += `<small>` + $localize`Around block: ${data[0].data[2]}` + `</small>`; |             tooltip += `<small>` + $localize`Around block: ${ticks[0].data[2]}` + `</small>`; | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           return tooltip; |           return tooltip; | ||||||
|         }.bind(this) |         } | ||||||
|       }, |       }, | ||||||
|       xAxis: data.length === 0 ? undefined : |       xAxis: data.length === 0 ? undefined : | ||||||
|       { |       { | ||||||
| @ -243,15 +187,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|       legend: { |       legend: { | ||||||
|         data: [ |         data: [ | ||||||
|           { |           { | ||||||
|             name: 'In-band fees per block', |             name: 'Total bid boost', | ||||||
|             inactiveColor: 'rgb(110, 112, 121)', |  | ||||||
|             textStyle: { |  | ||||||
|               color: 'white', |  | ||||||
|             }, |  | ||||||
|             icon: 'roundRect', |  | ||||||
|           }, |  | ||||||
|           { |  | ||||||
|             name: 'Total bid boost per block', |  | ||||||
|             inactiveColor: 'rgb(110, 112, 121)', |             inactiveColor: 'rgb(110, 112, 121)', | ||||||
|             textStyle: { |             textStyle: { | ||||||
|               color: 'white', |               color: 'white', | ||||||
| @ -260,8 +196,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|           }, |           }, | ||||||
|         ], |         ], | ||||||
|         selected: { |         selected: { | ||||||
|           'In-band fees per block': false, |           'Total bid boost': true, | ||||||
|           'Total bid boost per block': true, |  | ||||||
|         }, |         }, | ||||||
|         show: !this.widget, |         show: !this.widget, | ||||||
|       }, |       }, | ||||||
| @ -304,21 +239,13 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { | |||||||
|         { |         { | ||||||
|           legendHoverLink: false, |           legendHoverLink: false, | ||||||
|           zlevel: 1, |           zlevel: 1, | ||||||
|           name: 'Total bid boost per block', |           name: 'Total bid boost', | ||||||
|           data: data.map(block =>  [block.timestamp * 1000, block.avgFeePaid, block.avgHeight]), |           data: data.map(h =>  { | ||||||
|  |             return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight] | ||||||
|  |           }), | ||||||
|           stack: 'Total', |           stack: 'Total', | ||||||
|           type: 'bar', |           type: 'bar', | ||||||
|           barWidth: '100%', |           barWidth: '90%', | ||||||
|           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%', |  | ||||||
|           large: true, |           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
 |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,12 +22,12 @@ | |||||||
|     <div class="col"> |     <div class="col"> | ||||||
|       <div class="main-title"> |       <div class="main-title"> | ||||||
|         <span [attr.data-cy]="'acceleration-stats'" i18n="accelerator.acceleration-stats">Acceleration stats</span>  |         <span [attr.data-cy]="'acceleration-stats'" i18n="accelerator.acceleration-stats">Acceleration stats</span>  | ||||||
|         <span style="font-size: xx-small" i18n="mining.144-blocks">(1 month)</span> |         <span style="font-size: xx-small" i18n="mining.3-months">(3 months)</span> | ||||||
|       </div> |       </div> | ||||||
|       <div class="card-wrapper"> |       <div class="card-wrapper"> | ||||||
|         <div class="card"> |         <div class="card"> | ||||||
|           <div class="card-body more-padding"> |           <div class="card-body more-padding"> | ||||||
|             <app-acceleration-stats timespan="1m"></app-acceleration-stats> |             <app-acceleration-stats></app-acceleration-stats> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
| @ -59,7 +59,6 @@ | |||||||
|               [height]="graphHeight" |               [height]="graphHeight" | ||||||
|               [attr.data-cy]="'acceleration-fees'" |               [attr.data-cy]="'acceleration-fees'" | ||||||
|               [widget]=true |               [widget]=true | ||||||
|               [accelerations$]="accelerations$" |  | ||||||
|             ></app-acceleration-fees-graph> |             ></app-acceleration-fees-graph> | ||||||
|           </div> |           </div> | ||||||
|           <div class="mt-1"><a [attr.data-cy]="'acceleration-fees-view-more'" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div> |           <div class="mt-1"><a [attr.data-cy]="'acceleration-fees-view-more'" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div> | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ export class AcceleratorDashboardComponent implements OnInit { | |||||||
|     this.accelerations$ = this.stateService.chainTip$.pipe( |     this.accelerations$ = this.stateService.chainTip$.pipe( | ||||||
|       distinctUntilChanged(), |       distinctUntilChanged(), | ||||||
|       switchMap(() => { |       switchMap(() => { | ||||||
|         return this.serviceApiServices.getAccelerationHistory$({ timeframe: '1m', page: 1, pageLength: 100}).pipe( |         return this.serviceApiServices.getAccelerationHistory$({ timeframe: '3m', page: 1, pageLength: 100}).pipe( | ||||||
|           catchError(() => { |           catchError(() => { | ||||||
|             return of([]); |             return of([]); | ||||||
|           }), |           }), | ||||||
|  | |||||||
| @ -145,6 +145,10 @@ export class ServicesApiServices { | |||||||
|     return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations`); |     return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   getAggregatedAccelerationHistory$(params: AccelerationHistoryParams): Observable<Acceleration[]> { | ||||||
|  |     return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations/history/aggregated`, { params: { ...params } }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   getAccelerationHistory$(params: AccelerationHistoryParams): Observable<Acceleration[]> { |   getAccelerationHistory$(params: AccelerationHistoryParams): Observable<Acceleration[]> { | ||||||
|     return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations/history`, { params: { ...params } }); |     return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations/history`, { params: { ...params } }); | ||||||
|   } |   } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user