Reversible mempool block visualization

This commit is contained in:
Mononaut 2022-09-29 22:40:46 +00:00
parent 03c6a7c54f
commit 135fbfc4f3
No known key found for this signature in database
GPG key ID: 61B952CAF4838F94
4 changed files with 51 additions and 10 deletions

View file

@ -1,4 +1,4 @@
import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy } from '@angular/core';
import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy, OnChanges } from '@angular/core';
import { TransactionStripped } from '../../interfaces/websocket.interface';
import { FastVertexArray } from './fast-vertex-array';
import BlockScene from './block-scene';
@ -11,7 +11,7 @@ import { Position } from './sprite-types';
templateUrl: './block-overview-graph.component.html',
styleUrls: ['./block-overview-graph.component.scss'],
})
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy {
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges {
@Input() isLoading: boolean;
@Input() resolution: number;
@Input() blockLimit: number;
@ -57,6 +57,14 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy {
this.resizeCanvas();
}
ngOnChanges(changes): void {
if (changes.orientation || changes.flip) {
if (this.scene) {
this.scene.setOrientation(this.orientation, this.flip);
}
}
}
ngOnDestroy(): void {
if (this.animationFrameRequest) {
cancelAnimationFrame(this.animationFrameRequest);

View file

@ -42,6 +42,24 @@ export default class BlockScene {
}
}
setOrientation(orientation: string, flip: boolean): void {
this.orientation = orientation;
this.flip = flip;
this.dirty = true;
const startTime = performance.now();
Object.values(this.txs).forEach(txView => {
this.saveGridToScreenPosition(txView);
this.applyTxUpdate(txView, {
display: {
position: txView.screenPosition,
color: txView.getColor()
},
duration: 0
});
this.setTxOnScreen(txView, startTime, 0);
});
}
// Destroy the current layout and clean up graphics sprites without any exit animation
destroy(): void {
Object.values(this.txs).forEach(tx => tx.destroy());

View file

@ -3,7 +3,7 @@
[isLoading]="isLoading$ | async"
[resolution]="75"
[blockLimit]="stateService.blockVSize"
[orientation]="'left'"
[orientation]="timeLtr ? 'right' : 'left'"
[flip]="true"
(txClickEvent)="onTxClick($event)"
></app-block-overview-graph>

View file

@ -1,5 +1,5 @@
import { Component, ComponentRef, ViewChild, HostListener, Input, Output, EventEmitter,
OnDestroy, OnChanges, ChangeDetectionStrategy, AfterViewInit } from '@angular/core';
OnInit, OnDestroy, OnChanges, ChangeDetectionStrategy, ChangeDetectorRef, AfterViewInit } from '@angular/core';
import { StateService } from '../../services/state.service';
import { MempoolBlockDelta, TransactionStripped } from '../../interfaces/websocket.interface';
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
@ -14,7 +14,7 @@ import { Router } from '@angular/router';
templateUrl: './mempool-block-overview.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, AfterViewInit {
export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
@Input() index: number;
@Output() txPreviewEvent = new EventEmitter<TransactionStripped | void>();
@ -23,6 +23,10 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
lastBlockHeight: number;
blockIndex: number;
isLoading$ = new BehaviorSubject<boolean>(true);
timeLtrSubscription: Subscription;
timeLtr: boolean;
chainDirection: string = 'right';
poolDirection: string = 'left';
blockSub: Subscription;
deltaSub: Subscription;
@ -31,8 +35,18 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
public stateService: StateService,
private websocketService: WebsocketService,
private router: Router,
private cd: ChangeDetectorRef,
) { }
ngOnInit(): void {
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
this.timeLtr = !!ltr;
this.chainDirection = ltr ? 'left' : 'right';
this.poolDirection = ltr ? 'right' : 'left';
this.cd.markForCheck();
});
}
ngAfterViewInit(): void {
this.blockSub = merge(
of(true),
@ -50,7 +64,7 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
ngOnChanges(changes): void {
if (changes.index) {
if (this.blockGraph) {
this.blockGraph.clear(changes.index.currentValue > changes.index.previousValue ? 'right' : 'left');
this.blockGraph.clear(changes.index.currentValue > changes.index.previousValue ? this.chainDirection : this.poolDirection);
}
this.isLoading$.next(true);
this.websocketService.startTrackMempoolBlock(changes.index.currentValue);
@ -60,16 +74,17 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
ngOnDestroy(): void {
this.blockSub.unsubscribe();
this.deltaSub.unsubscribe();
this.timeLtrSubscription.unsubscribe();
this.websocketService.stopTrackMempoolBlock();
}
replaceBlock(transactionsStripped: TransactionStripped[]): void {
const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight);
if (this.blockIndex !== this.index) {
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? 'left' : 'right';
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection;
this.blockGraph.enter(transactionsStripped, direction);
} else {
this.blockGraph.replace(transactionsStripped, blockMined ? 'right' : 'left');
this.blockGraph.replace(transactionsStripped, blockMined ? this.chainDirection : this.poolDirection);
}
this.lastBlockHeight = this.stateService.latestBlockHeight;
@ -81,10 +96,10 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight);
if (this.blockIndex !== this.index) {
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? 'left' : 'right';
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection;
this.blockGraph.replace(delta.added, direction);
} else {
this.blockGraph.update(delta.added, delta.removed, blockMined ? 'right' : 'left', blockMined);
this.blockGraph.update(delta.added, delta.removed, blockMined ? this.chainDirection : this.poolDirection, blockMined);
}
this.lastBlockHeight = this.stateService.latestBlockHeight;