diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index 15e41f1a7..583f9875c 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -6,6 +6,8 @@ import TxSprite from './tx-sprite'; import TxView from './tx-view'; import { Position } from './sprite-types'; import { Price } from '../../services/price.service'; +import { StateService } from '../../services/state.service'; +import { Subscription } from 'rxjs'; @Component({ selector: 'app-block-overview-graph', @@ -44,16 +46,25 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On scene: BlockScene; hoverTx: TxView | void; selectedTx: TxView | void; + highlightTx: TxView | void; mirrorTx: TxView | void; tooltipPosition: Position; readyNextFrame = false; + searchText: string; + searchSubscription: Subscription; + constructor( readonly ngZone: NgZone, readonly elRef: ElementRef, + private stateService: StateService, ) { this.vertexArray = new FastVertexArray(512, TxSprite.dataSize); + this.searchSubscription = this.stateService.searchText$.subscribe((text) => { + this.searchText = text; + this.updateSearchHighlight(); + }); } ngAfterViewInit(): void { @@ -109,6 +120,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On this.scene.setup(transactions); this.readyNextFrame = true; this.start(); + this.updateSearchHighlight(); } } @@ -116,6 +128,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On if (this.scene) { this.scene.enter(transactions, direction); this.start(); + this.updateSearchHighlight(); } } @@ -123,6 +136,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On if (this.scene) { this.scene.exit(direction); this.start(); + this.updateSearchHighlight(); } } @@ -130,6 +144,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On if (this.scene) { this.scene.replace(transactions || [], direction, sort); this.start(); + this.updateSearchHighlight(); } } @@ -137,6 +152,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On if (this.scene) { this.scene.update(add, remove, change, direction, resetLayout); this.start(); + this.updateSearchHighlight(); } } @@ -406,6 +422,19 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On } } + updateSearchHighlight(): void { + if (this.highlightTx && this.highlightTx.txid !== this.searchText && this.scene) { + this.scene.setHighlight(this.highlightTx, false); + this.start(); + } else if (this.searchText && this.searchText.length === 64) { + this.highlightTx = this.scene.txs[this.searchText]; + if (this.highlightTx) { + this.scene.setHighlight(this.highlightTx, true); + this.start(); + } + } + } + setHighlightingEnabled(enabled: boolean): void { if (this.scene) { this.scene.setHighlighting(enabled); diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts index 0cd5c9391..e7241141d 100644 --- a/frontend/src/app/components/block-overview-graph/block-scene.ts +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -215,6 +215,10 @@ export default class BlockScene { this.animateUntil = Math.max(this.animateUntil, tx.setHover(value)); } + setHighlight(tx: TxView, value: boolean): void { + this.animateUntil = Math.max(this.animateUntil, tx.setHighlight(value)); + } + private init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting, pixelAlign }: { width: number, height: number, resolution: number, blockLimit: number, orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, pixelAlign: boolean } diff --git a/frontend/src/app/components/block-overview-graph/tx-view.ts b/frontend/src/app/components/block-overview-graph/tx-view.ts index 7d3e0ee13..77f5a182a 100644 --- a/frontend/src/app/components/block-overview-graph/tx-view.ts +++ b/frontend/src/app/components/block-overview-graph/tx-view.ts @@ -7,6 +7,7 @@ import BlockScene from './block-scene'; const hoverTransitionTime = 300; const defaultHoverColor = hexToColor('1bd8f4'); +const defaultHighlightColor = hexToColor('800080'); const feeColors = mempoolFeeColors.map(hexToColor); const auditFeeColors = feeColors.map((color) => darken(desaturate(color, 0.3), 0.9)); @@ -44,8 +45,10 @@ export default class TxView implements TransactionStripped { initialised: boolean; vertexArray: FastVertexArray; hover: boolean; + highlight: boolean; sprite: TxSprite; hoverColor: Color | void; + highlightColor: Color | void; screenPosition: Square; gridPosition: Square | void; @@ -150,8 +153,40 @@ export default class TxView implements TransactionStripped { } else { this.hover = false; this.hoverColor = null; - if (this.sprite) { - this.sprite.resume(hoverTransitionTime); + if (this.highlight) { + this.setHighlight(true, this.highlightColor); + } else { + if (this.sprite) { + this.sprite.resume(hoverTransitionTime); + } + } + } + this.dirty = false; + return performance.now() + hoverTransitionTime; + } + + // Temporarily override the tx color + // returns minimum transition end time + setHighlight(highlightOn: boolean, color: Color | void = defaultHighlightColor): number { + if (highlightOn) { + this.highlight = true; + this.highlightColor = color; + + this.sprite.update({ + ...this.highlightColor, + duration: hoverTransitionTime, + adjust: false, + temp: true + }); + } else { + this.highlight = false; + this.highlightColor = null; + if (this.hover) { + this.setHover(true, this.hoverColor); + } else { + if (this.sprite) { + this.sprite.resume(hoverTransitionTime); + } } } this.dirty = false; diff --git a/frontend/src/app/components/search-form/search-form.component.ts b/frontend/src/app/components/search-form/search-form.component.ts index 422cb2f45..ab42fe1f7 100644 --- a/frontend/src/app/components/search-form/search-form.component.ts +++ b/frontend/src/app/components/search-form/search-form.component.ts @@ -80,6 +80,9 @@ export class SearchFormComponent implements OnInit { } return text.trim(); }), + tap((text) => { + this.stateService.searchText$.next(text); + }), distinctUntilChanged(), ); diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index f38600605..16252a9ec 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -129,6 +129,7 @@ export class StateService { markBlock$ = new BehaviorSubject({}); keyNavigation$ = new Subject(); + searchText$ = new BehaviorSubject(''); blockScrolling$: Subject = new Subject(); resetScroll$: Subject = new Subject();