import { Component, OnInit, Input, Output, OnChanges, EventEmitter, HostListener, Inject, LOCALE_ID } from '@angular/core'; import { StateService } from '../../services/state.service'; import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.interface'; import { Router } from '@angular/router'; import { ReplaySubject, merge, Subscription, of } from 'rxjs'; import { tap, switchMap } from 'rxjs/operators'; import { ApiService } from '../../services/api.service'; import { AccelerationEstimate, RateOption } from './accelerate-checkout.component'; interface GraphBar { rate: number; style: any; class: 'tx' | 'target' | 'max'; label: string; active?: boolean; rateIndex?: number; fee?: number; } @Component({ selector: 'app-accelerate-fee-graph', templateUrl: './accelerate-fee-graph.component.html', styleUrls: ['./accelerate-fee-graph.component.scss'], }) export class AccelerateFeeGraphComponent implements OnInit, OnChanges { @Input() tx: Transaction; @Input() estimate: AccelerationEstimate; @Input() showEstimate = false; @Input() maxRateOptions: RateOption[] = []; @Input() maxRateIndex: number = 0; @Output() setUserBid = new EventEmitter<{ fee: number, index: number }>(); bars: GraphBar[] = []; tooltipPosition = { x: 0, y: 0 }; ngOnInit(): void { this.initGraph(); } ngOnChanges(): void { this.initGraph(); } initGraph(): void { if (!this.tx || !this.estimate) { return; } const maxRate = Math.max(...this.maxRateOptions.map(option => option.rate)); const baseRate = this.estimate.txSummary.effectiveFee / this.estimate.txSummary.effectiveVsize; const baseHeight = baseRate / maxRate; const bars: GraphBar[] = this.maxRateOptions.slice().reverse().map(option => { return { rate: option.rate, style: this.getStyle(option.rate, maxRate, baseHeight), class: 'max', label: this.showEstimate ? $localize`maximum` : $localize`:@@25fbf6e80a945703c906a5a7d8c92e8729c7ab21:accelerated`, active: option.index === this.maxRateIndex, rateIndex: option.index, fee: option.fee, } }); if (this.estimate.nextBlockFee > this.estimate.txSummary.effectiveFee) { bars.push({ rate: this.estimate.targetFeeRate, style: this.getStyle(this.estimate.targetFeeRate, maxRate, baseHeight), class: 'target', label: $localize`:@@bdf0e930eb22431140a2eaeacd809cc5f8ebd38c:Next Block`.toLowerCase(), fee: this.estimate.nextBlockFee - this.estimate.txSummary.effectiveFee }); } bars.push({ rate: baseRate, style: this.getStyle(baseRate, maxRate, 0), class: 'tx', label: '', fee: this.estimate.txSummary.effectiveFee, }); this.bars = bars; } getStyle(rate, maxRate, base) { const top = (rate / maxRate); return { height: `${(top - base) * 100}%`, bottom: base ? `${base * 100}%` : '0', } } onClick(event, bar): void { if (bar.rateIndex != null) { this.setUserBid.emit({ fee: bar.fee, index: bar.rateIndex }); } } @HostListener('pointermove', ['$event']) onPointerMove(event) { this.tooltipPosition = { x: event.offsetX, y: event.offsetY }; } }