Reimplement mempool animation smoothing within viz component

This commit is contained in:
Mononaut 2024-05-02 23:48:56 +00:00
parent a8868b5f0f
commit 44116424b0
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
3 changed files with 76 additions and 4 deletions

View File

@ -81,6 +81,20 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
tooltipPosition: Position;
readyNextFrame = false;
lastUpdate: number = 0;
pendingUpdate: {
count: number,
add: { [txid: string]: TransactionStripped },
remove: { [txid: string]: string },
change: { [txid: string]: { txid: string, rate: number | undefined, acc: boolean | undefined } },
direction?: string,
} = {
count: 0,
add: {},
remove: {},
change: {},
direction: 'left',
};
searchText: string;
searchSubscription: Subscription;
@ -176,6 +190,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
destroy(): void {
if (this.scene) {
this.scene.destroy();
this.clearUpdateQueue();
this.start();
}
}
@ -188,6 +203,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
}
this.filtersAvailable = filtersAvailable;
if (this.scene) {
this.clearUpdateQueue();
this.scene.setup(transactions);
this.readyNextFrame = true;
this.start();
@ -197,6 +213,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
enter(transactions: TransactionStripped[], direction: string): void {
if (this.scene) {
this.clearUpdateQueue();
this.scene.enter(transactions, direction);
this.start();
this.updateSearchHighlight();
@ -205,6 +222,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
exit(direction: string): void {
if (this.scene) {
this.clearUpdateQueue();
this.scene.exit(direction);
this.start();
this.updateSearchHighlight();
@ -213,13 +231,61 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
replace(transactions: TransactionStripped[], direction: string, sort: boolean = true, startTime?: number): void {
if (this.scene) {
this.clearUpdateQueue();
this.scene.replace(transactions || [], direction, sort, startTime);
this.start();
this.updateSearchHighlight();
}
}
// collates non-urgent updates into a set of consistent pending changes
queueUpdate(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left'): void {
for (const tx of add) {
this.pendingUpdate.add[tx.txid] = tx;
delete this.pendingUpdate.remove[tx.txid];
delete this.pendingUpdate.change[tx.txid];
}
for (const txid of remove) {
delete this.pendingUpdate.add[txid];
this.pendingUpdate.remove[txid] = txid;
delete this.pendingUpdate.change[txid];
}
for (const tx of change) {
if (this.pendingUpdate.add[tx.txid]) {
this.pendingUpdate.add[tx.txid].rate = tx.rate;
this.pendingUpdate.add[tx.txid].acc = tx.acc;
} else {
this.pendingUpdate.change[tx.txid] = tx;
}
}
this.pendingUpdate.direction = direction;
this.pendingUpdate.count++;
}
applyQueuedUpdates(): void {
if (this.pendingUpdate.count && performance.now() > (this.lastUpdate + this.animationDuration)) {
this.update([], [], [], this.pendingUpdate?.direction);
}
}
clearUpdateQueue(): void {
this.pendingUpdate = {
count: 0,
add: {},
remove: {},
change: {},
};
this.lastUpdate = performance.now();
}
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
// merge any pending changes into this update
this.queueUpdate(add, remove, change);
this.applyUpdate(Object.values(this.pendingUpdate.add), Object.values(this.pendingUpdate.remove), Object.values(this.pendingUpdate.change), direction, resetLayout);
this.clearUpdateQueue();
}
applyUpdate(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
if (this.scene) {
add = add.filter(tx => !this.scene.txs[tx.txid]);
remove = remove.filter(txid => this.scene.txs[txid]);
@ -230,6 +296,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
}
this.scene.update(add, remove, change, direction, resetLayout);
this.start();
this.lastUpdate = performance.now();
this.updateSearchHighlight();
}
}
@ -370,6 +437,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
if (!now) {
now = performance.now();
}
this.applyQueuedUpdates();
// skip re-render if there's no change to the scene
if (this.scene && this.gl) {
/* SET UP SHADER UNIFORMS */

View File

@ -13,7 +13,7 @@ export default class BlockScene {
theme: ThemeService;
orientation: string;
flip: boolean;
animationDuration: number = 900;
animationDuration: number = 1000;
configAnimationOffset: number | null;
animationOffset: number;
highlightingEnabled: boolean;
@ -179,7 +179,7 @@ export default class BlockScene {
removed.forEach(tx => {
tx.destroy();
});
}, 1000);
}, (startTime - performance.now()) + this.animationDuration + 1000);
if (resetLayout) {
add.forEach(tx => {
@ -239,7 +239,7 @@ export default class BlockScene {
{ width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number,
orientation: string, flip: boolean, vertexArray: FastVertexArray, theme: ThemeService, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null }
): void {
this.animationDuration = animationDuration || 1000;
this.animationDuration = animationDuration || this.animationDuration || 1000;
this.configAnimationOffset = animationOffset;
this.animationOffset = this.configAnimationOffset == null ? (this.width * 1.4) : this.configAnimationOffset;
this.orientation = orientation;

View File

@ -141,7 +141,11 @@ export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChang
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, delta.changed || [], blockMined ? this.chainDirection : this.poolDirection, blockMined);
if (blockMined) {
this.blockGraph.update(delta.added, delta.removed, delta.changed || [], blockMined ? this.chainDirection : this.poolDirection, blockMined);
} else {
this.blockGraph.queueUpdate(delta.added, delta.removed, delta.changed || [], this.poolDirection);
}
}
this.lastBlockHeight = this.stateService.latestBlockHeight;