Projected block overview mouse events & tx preview

This commit is contained in:
Mononaut
2022-05-31 14:16:35 +00:00
parent 866361760c
commit ce276e3a7d
5 changed files with 158 additions and 32 deletions

View File

@@ -1,6 +1,6 @@
import TxSprite from './tx-sprite'
import TxView from './tx-view'
import { Square } from './sprite-types'
import { Position, Square } from './sprite-types'
export default class BlockScene {
scene: { count: number, offset: { x: number, y: number}};
@@ -33,6 +33,7 @@ export default class BlockScene {
this.unitWidth = this.gridSize - (this.unitPadding * 2)
this.dirty = true
if (this.initialised && this.scene) this.updateAll(performance.now())
}
// Animate new block entering scene
@@ -70,6 +71,14 @@ export default class BlockScene {
})
}
//return the tx at this screen position, if any
getTxAt (position: Position): TxView | void {
if (this.layout) {
const gridPosition = this.screenToGrid(position)
return this.layout.getTx(gridPosition)
} else return null
}
private init ({ width, height, resolution, blockLimit }: { width: number, height: number, resolution: number, blockLimit: number}): void {
this.scene = {
count: 0,
@@ -205,6 +214,14 @@ export default class BlockScene {
}
}
screenToGrid (position: Position): Position {
const grid = {
x: Math.floor((position.y - this.unitPadding) / this.gridSize),
y: Math.floor((this.width + (this.unitPadding * 2) - position.x) / this.gridSize)
}
return grid
}
// calculates and returns the size of the tx in multiples of the grid size
private txSize (tx: TxView): number {
let scale = Math.max(1,Math.round(Math.sqrt(tx.vsize / this.vbytesPerUnit)))
@@ -328,6 +345,14 @@ class Row {
}
}
}
txAt (x: number): TxView | void {
let i = 0
while (i < this.filled.length && this.filled[i].l <= x) {
if (this.filled[i].l <= x && this.filled[i].r > x) return this.filled[i].tx
i++
}
}
}
class BlockLayout {
@@ -344,6 +369,16 @@ class BlockLayout {
this.txPositions = {}
}
getRow (position: Square): Row {
return this.rows[position.y]
}
getTx (position: Square): TxView | void {
if (this.getRow(position)) {
return this.getRow(position).txAt(position.x)
}
}
addRow (): void {
this.rows.push(new Row(this.rows.length, this.width))
}

View File

@@ -1,6 +1,6 @@
import { Component, ElementRef, ViewChild, HostListener, Input, OnInit, OnDestroy, OnChanges, ChangeDetectionStrategy, NgZone } from '@angular/core';
import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, OnInit, OnDestroy, OnChanges, ChangeDetectionStrategy, NgZone } from '@angular/core';
import { StateService } from 'src/app/services/state.service';
import { MempoolBlockWithTransactions } from 'src/app/interfaces/websocket.interface';
import { MempoolBlockWithTransactions, TransactionStripped } from 'src/app/interfaces/websocket.interface';
import { Observable, Subscription } from 'rxjs';
import { WebsocketService } from 'src/app/services/websocket.service';
import { FastVertexArray } from './fast-vertex-array';
@@ -16,6 +16,7 @@ import TxView from './tx-view';
})
export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChanges {
@Input() index: number;
@Output() txPreviewEvent = new EventEmitter<TransactionStripped | void>()
@ViewChild('blockCanvas')
canvas: ElementRef<HTMLCanvasElement>;
@@ -29,6 +30,8 @@ export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChang
running: boolean;
scene: BlockScene;
txViews: { [key: string]: TxView };
hoverTx: TxView | void;
selectedTx: TxView | void;
lastBlockHeight: number;
blockIndex: number;
@@ -259,6 +262,56 @@ export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChang
this.animationFrameRequest = requestAnimationFrame(() => this.run());
}
}
@HostListener('click', ['$event'])
onClick(event) {
this.setPreviewTx(event.offsetX, event.offsetY, true)
}
@HostListener('pointermove', ['$event'])
onPointerMove(event) {
this.setPreviewTx(event.offsetX, event.offsetY, false)
}
@HostListener('pointerleave', ['$event'])
onPointerLeave(event) {
this.setPreviewTx(-1, -1, false)
}
setPreviewTx(x: number, y: number, clicked: boolean = false) {
if (this.scene && (!this.selectedTx || clicked)) {
const selected = this.scene.getTxAt({ x, y })
const currentPreview = this.selectedTx || this.hoverTx
if (selected !== currentPreview) {
if (currentPreview) currentPreview.setHover(false)
if (selected) {
selected.setHover(true)
this.txPreviewEvent.emit({
txid: selected.txid,
fee: selected.fee,
vsize: selected.vsize,
value: selected.value
})
if (clicked) this.selectedTx = selected
else this.hoverTx = selected
} else {
if (clicked) {
this.selectedTx = null
}
this.hoverTx = null
this.txPreviewEvent.emit(null)
}
} else if (clicked) {
if (selected === this.selectedTx) {
this.hoverTx = this.selectedTx
this.selectedTx = null
} else {
this.selectedTx = selected
}
}
}
}
}
// WebGL shader attributes