From c10ace8fb5819c3b80692b6ee7076ad2dc2f0fc1 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 4 Oct 2022 21:00:46 +0000 Subject: [PATCH] Scroll to input/output when clicked in tx diagram --- .../transaction/transaction.component.html | 7 +- .../transaction/transaction.component.ts | 11 +++ .../transactions-list.component.html | 10 +-- .../transactions-list.component.ts | 84 +++++++++++-------- .../tx-bowtie-graph-tooltip.component.html | 2 +- .../tx-bowtie-graph.component.html | 2 + .../tx-bowtie-graph.component.ts | 22 +++-- 7 files changed, 88 insertions(+), 50 deletions(-) diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 5b35fc7b1..dcd59a1f8 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -208,7 +208,10 @@ [lineLimit]="inOutLimit" [maxStrands]="graphExpanded ? maxInOut : 24" [network]="network" - [tooltip]="true"> + [tooltip]="true" + (selectInput)="selectInput($event)" + (selectOutput)="selectOutput($event)" + >
@@ -240,7 +243,7 @@
- +

Details

diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 1db6e8f09..8aa313c81 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -47,6 +47,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { now = new Date().getTime(); timeAvg$: Observable; liquidUnblinding = new LiquidUnblinding(); + inputIndex: number; outputIndex: number; showFlow: boolean = true; graphExpanded: boolean = false; @@ -334,6 +335,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.graphExpanded = false; } + selectInput(input) { + this.inputIndex = input; + this.outputIndex = null; + } + + selectOutput(output) { + this.outputIndex = output; + this.inputIndex = null; + } + @HostListener('window:resize', ['$event']) setGraphSize(): void { if (this.graphContainer) { diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index 81c3dce5c..e26740aa5 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -20,9 +20,9 @@
- + - + @@ -158,7 +158,7 @@
@@ -146,7 +146,7 @@
- + rowLimit && tx['@voutLimit'] && !outputIndex"> + diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index 8fd81af51..03c2d59ee 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -24,6 +24,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { @Input() transactionPage = false; @Input() errorUnblinded = false; @Input() paginated = false; + @Input() inputIndex: number; @Input() outputIndex: number; @Input() address: string = ''; @Input() rowLimit = 12; @@ -37,6 +38,8 @@ export class TransactionsListComponent implements OnInit, OnChanges { showDetails$ = new BehaviorSubject(false); assetsMinimal: any; transactionsLength: number = 0; + inputRowLimit: number = 12; + outputRowLimit: number = 12; constructor( public stateService: StateService, @@ -97,50 +100,57 @@ export class TransactionsListComponent implements OnInit, OnChanges { ).subscribe(() => this.ref.markForCheck()); } - ngOnChanges(): void { - if (!this.transactions || !this.transactions.length) { - return; + ngOnChanges(changes): void { + if (changes.inputIndex || changes.outputIndex || changes.rowLimit) { + this.inputRowLimit = Math.max(this.rowLimit, (this.inputIndex || 0) + 3); + this.outputRowLimit = Math.max(this.rowLimit, (this.outputIndex || 0) + 3); + if (this.inputIndex || this.outputIndex) { + setTimeout(() => { + const assetBoxElements = document.getElementsByClassName('assetBox'); + if (assetBoxElements && assetBoxElements[0]) { + assetBoxElements[0].scrollIntoView({block: "center"}); + } + }, 10); + } } - - this.transactionsLength = this.transactions.length; - if (this.outputIndex) { - setTimeout(() => { - const assetBoxElements = document.getElementsByClassName('assetBox'); - if (assetBoxElements && assetBoxElements[0]) { - assetBoxElements[0].scrollIntoView(); - } - }, 10); - } - - this.transactions.forEach((tx) => { - tx['@voutLimit'] = true; - tx['@vinLimit'] = true; - if (tx['addressValue'] !== undefined) { + if (changes.transactions || changes.address) { + if (!this.transactions || !this.transactions.length) { return; } - if (this.address) { - const addressIn = tx.vout - .filter((v: Vout) => v.scriptpubkey_address === this.address) - .map((v: Vout) => v.value || 0) - .reduce((a: number, b: number) => a + b, 0); + this.transactionsLength = this.transactions.length; - const addressOut = tx.vin - .filter((v: Vin) => v.prevout && v.prevout.scriptpubkey_address === this.address) - .map((v: Vin) => v.prevout.value || 0) - .reduce((a: number, b: number) => a + b, 0); - tx['addressValue'] = addressIn - addressOut; - } - }); - const txIds = this.transactions.filter((tx) => !tx._outspends).map((tx) => tx.txid); - if (txIds.length) { - this.refreshOutspends$.next(txIds); - } - if (this.stateService.env.LIGHTNING) { - const txIds = this.transactions.filter((tx) => !tx._channels).map((tx) => tx.txid); + this.transactions.forEach((tx) => { + tx['@voutLimit'] = true; + tx['@vinLimit'] = true; + if (tx['addressValue'] !== undefined) { + return; + } + + if (this.address) { + const addressIn = tx.vout + .filter((v: Vout) => v.scriptpubkey_address === this.address) + .map((v: Vout) => v.value || 0) + .reduce((a: number, b: number) => a + b, 0); + + const addressOut = tx.vin + .filter((v: Vin) => v.prevout && v.prevout.scriptpubkey_address === this.address) + .map((v: Vin) => v.prevout.value || 0) + .reduce((a: number, b: number) => a + b, 0); + + tx['addressValue'] = addressIn - addressOut; + } + }); + const txIds = this.transactions.filter((tx) => !tx._outspends).map((tx) => tx.txid); if (txIds.length) { - this.refreshChannels$.next(txIds); + this.refreshOutspends$.next(txIds); + } + if (this.stateService.env.LIGHTNING) { + const txIds = this.transactions.filter((tx) => !tx._channels).map((tx) => tx.txid); + if (txIds.length) { + this.refreshChannels$.next(txIds); + } } } } diff --git a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html index 563e6ed00..6872438a0 100644 --- a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html +++ b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html @@ -44,7 +44,7 @@ Output Fee - #{{ line.index }} + #{{ line.index + 1 }}

Confidential

diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html index 03056cd53..3f0143a67 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html @@ -60,6 +60,7 @@ attr.marker-start="url(#{{input.class}}-arrow)" (pointerover)="onHover($event, 'input', i);" (pointerout)="onBlur($event, 'input', i);" + (click)="onClick($event, 'input', inputData[i].index);" /> @@ -70,6 +71,7 @@ attr.marker-start="url(#{{output.class}}-arrow)" (pointerover)="onHover($event, 'output', i);" (pointerout)="onBlur($event, 'output', i);" + (click)="onClick($event, 'output', outputData[i].index);" /> diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts index 16e2736f7..592232955 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, OnChanges, HostListener } from '@angular/core'; +import { Component, OnInit, Input, Output, EventEmitter, OnChanges, HostListener } from '@angular/core'; import { Transaction } from '../../interfaces/electrs.interface'; interface SvgLine { @@ -35,6 +35,9 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { @Input() maxStrands = 24; // number of inputs/outputs to keep fully on-screen. @Input() tooltip = false; + @Output() selectInput = new EventEmitter(); + @Output() selectOutput = new EventEmitter(); + inputData: Xput[]; outputData: Xput[]; inputs: SvgLine[]; @@ -76,11 +79,12 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { this.combinedWeight = Math.min(this.maxCombinedWeight, Math.floor((this.width - (2 * this.midWidth)) / 6)); const totalValue = this.calcTotalValue(this.tx); - let voutWithFee = this.tx.vout.map(v => { + let voutWithFee = this.tx.vout.map((v, i) => { return { type: v.scriptpubkey_type === 'fee' ? 'fee' : 'output', value: v?.value, address: v?.scriptpubkey_address || v?.scriptpubkey_type?.toUpperCase(), + index: i, pegout: v?.pegout?.scriptpubkey_address, confidential: (this.isLiquid && v?.value === undefined), } as Xput; @@ -91,11 +95,12 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { } const outputCount = voutWithFee.length; - let truncatedInputs = this.tx.vin.map(v => { + let truncatedInputs = this.tx.vin.map((v, i) => { return { type: 'input', value: v?.prevout?.value, address: v?.prevout?.scriptpubkey_address || v?.prevout?.scriptpubkey_type?.toUpperCase(), + index: i, coinbase: v?.is_coinbase, pegin: v?.is_pegin, confidential: (this.isLiquid && v?.prevout?.value === undefined), @@ -306,8 +311,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { }; } else { this.hoverLine = { - ...this.outputData[index], - index + ...this.outputData[index] }; } } @@ -315,4 +319,12 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { onBlur(event, side, index): void { this.hoverLine = null; } + + onClick(event, side, index): void { + if (side === 'input') { + this.selectInput.emit(index); + } else { + this.selectOutput.emit(index); + } + } }