import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { echarts, EChartsOption } from '../../graphs/echarts'; import { of } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { ChainStats } from '../../interfaces/electrs.interface'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; @Component({ selector: 'app-address-graph', templateUrl: './address-graph.component.html', styleUrls: ['./address-graph.component.scss'], styles: [` .loadingGraphs { position: absolute; top: 50%; left: calc(50% - 15px); z-index: 100; } `], changeDetection: ChangeDetectionStrategy.OnPush, }) export class AddressGraphComponent implements OnInit, OnChanges { @Input() address: string; @Input() isPubkey: boolean = false; @Input() stats: ChainStats; @Input() right: number | string = 10; @Input() left: number | string = 70; chartOptions: EChartsOption = {}; chartInitOptions = { renderer: 'svg', }; error: any; isLoading = true; chartInstance: any = undefined; constructor( @Inject(LOCALE_ID) public locale: string, private electrsApiService: ElectrsApiService, private amountShortenerPipe: AmountShortenerPipe, private cd: ChangeDetectorRef, ) { } ngOnInit(): void { } ngOnChanges(changes: SimpleChanges): void { this.isLoading = true; (this.isPubkey ? this.electrsApiService.getScriptHashSummary$((this.address.length === 66 ? '21' : '41') + this.address + 'ac') : this.electrsApiService.getAddressSummary$(this.address)).pipe( catchError(e => { this.error = `Failed to fetch address balance history: ${e?.status || ''} ${e?.statusText || 'unknown error'}`; return of(null); }), ).subscribe(addressSummary => { if (addressSummary) { this.error = null; this.prepareChartOptions(addressSummary); } this.isLoading = false; this.cd.markForCheck(); }); } prepareChartOptions(summary): void { let total = (this.stats.funded_txo_sum - this.stats.spent_txo_sum); // + (summary[0]?.value || 0); const data = summary.map(d => { const balance = total; total -= d.value; return [d.time * 1000, balance, d]; }).reverse(); const maxValue = data.reduce((acc, d) => Math.max(acc, Math.abs(d[1])), 0); this.chartOptions = { color: [ new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: '#FDD835' }, { offset: 1, color: '#FB8C00' }, ]), ], animation: false, grid: { top: 20, bottom: 20, right: this.right, left: this.left, }, tooltip: { show: !this.isMobile(), trigger: 'axis', axisPointer: { type: 'line' }, backgroundColor: 'rgba(17, 19, 31, 1)', borderRadius: 4, shadowColor: 'rgba(0, 0, 0, 0.5)', textStyle: { color: '#b1b1b1', align: 'left', }, borderColor: '#000', formatter: function (data): string { const header = data.length === 1 ? `${data[0].data[2].txid.slice(0, 6)}...${data[0].data[2].txid.slice(-6)}` : `${data.length} transactions`; const date = new Date(data[0].data[0]).toLocaleTimeString(this.locale, { year: 'numeric', month: 'short', day: 'numeric' }); const val = data.reduce((total, d) => total + d.data[2].value, 0); const color = val === 0 ? '' : (val > 0 ? '#1a9436' : '#dc3545'); const symbol = val > 0 ? '+' : ''; return `