multiblock interactivity

This commit is contained in:
Mononaut 2024-10-17 08:25:40 +00:00
parent f7422f29dc
commit 580ac889df
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
5 changed files with 172 additions and 6 deletions

View File

@ -553,7 +553,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
x: cssX,
y: cssY
};
const selected = this.scene.getTxAt({ x, y });
const selected = this.scene.getTxAt({ x, y: this.displayHeight - y });
const currentPreview = this.selectedTx || this.hoverTx;
if (selected !== currentPreview) {
@ -627,7 +627,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
if (this.scene) {
const x = cssX * window.devicePixelRatio;
const y = cssY * window.devicePixelRatio;
const selected = this.scene.getTxAt({ x, y });
const selected = this.scene.getTxAt({ x, y: this.displayHeight - y });
if (selected && selected.txid) {
this.txClickEvent.emit({ tx: selected, keyModifier });
}

View File

@ -228,7 +228,11 @@ export default class BlockScene {
getTxAt(position: Position): TxView | void {
if (this.layout) {
const gridPosition = this.screenToGrid(position);
return this.layout.getTx(gridPosition);
if (gridPosition.x >= 0 && gridPosition.x < this.gridWidth && gridPosition.y >= 0 && gridPosition.y < this.gridHeight) {
return this.layout.getTx(gridPosition);
} else {
return null;
}
} else {
return null;
}
@ -465,7 +469,7 @@ export default class BlockScene {
private screenToGrid(position: Position): Position {
let x = position.x - this.x;
let y = this.height - (position.y - this.y);
let y = position.y - this.y;
let t;
switch (this.orientation) {

View File

@ -523,6 +523,141 @@ export class BlockOverviewMultiComponent implements AfterViewInit, OnDestroy, On
}
}
@HostListener('document:click', ['$event'])
clickAway(event) {
if (!this.elRef.nativeElement.contains(event.target)) {
const currentPreview = this.selectedTx || this.hoverTx;
if (currentPreview) {
for (const scene of this.scenes) {
if (scene) {
scene.setHover(currentPreview, false);
}
}
this.start();
}
this.hoverTx = null;
this.selectedTx = null;
this.onTxHover(null);
}
}
@HostListener('pointerup', ['$event'])
onClick(event) {
if (!this.canvas) {
return;
}
if (event.target === this.canvas.nativeElement && event.pointerType === 'touch') {
this.setPreviewTx(event.offsetX, event.offsetY, true);
} else if (event.target === this.canvas.nativeElement) {
const keyMod = event.shiftKey || event.ctrlKey || event.metaKey;
const middleClick = event.which === 2 || event.button === 1;
this.onTxClick(event.offsetX, event.offsetY, keyMod || middleClick);
}
}
@HostListener('pointermove', ['$event'])
onPointerMove(event) {
if (!this.canvas) {
return;
}
if (event.target === this.canvas.nativeElement) {
this.setPreviewTx(event.offsetX, event.offsetY, false);
} else {
this.onPointerLeave(event);
}
}
@HostListener('pointerleave', ['$event'])
onPointerLeave(event) {
if (event.pointerType !== 'touch') {
this.setPreviewTx(-1, -1, true);
}
}
setPreviewTx(cssX: number, cssY: number, clicked: boolean = false) {
const x = cssX * window.devicePixelRatio;
const y = cssY * window.devicePixelRatio;
if (!this.selectedTx || clicked) {
this.tooltipPosition = {
x: cssX,
y: cssY
};
const currentPreview = this.selectedTx || this.hoverTx;
let selected;
for (const scene of this.scenes) {
if (scene) {
selected = scene.getTxAt({ x, y: this.displayHeight - y });
if (selected) {
break;
}
}
}
if (selected !== currentPreview) {
if (currentPreview) {
for (const scene of this.scenes) {
if (scene) {
scene.setHover(currentPreview, false);
break;
}
}
this.start();
}
if (selected) {
for (const scene of this.scenes) {
if (scene) {
scene.setHover(selected, true);
break;
}
}
this.start();
if (clicked) {
this.selectedTx = selected;
} else {
this.hoverTx = selected;
this.onTxHover(this.hoverTx ? this.hoverTx.txid : null);
}
} else {
if (clicked) {
this.selectedTx = null;
}
this.hoverTx = null;
this.onTxHover(null);
}
} else if (clicked) {
if (selected === this.selectedTx) {
this.hoverTx = this.selectedTx;
this.selectedTx = null;
this.onTxHover(this.hoverTx ? this.hoverTx.txid : null);
} else {
this.selectedTx = selected;
}
}
}
}
updateSearchHighlight(): void {
if (this.highlightTx && this.highlightTx.txid !== this.searchText) {
for (const scene of this.scenes) {
if (scene) {
scene.setHighlight(this.highlightTx, false);
}
}
this.start();
} else if (this.searchText && this.searchText.length === 64) {
for (const scene of this.scenes) {
if (scene) {
const highlightTx = scene.txs[this.searchText];
if (highlightTx) {
scene.setHighlight(highlightTx, true);
this.highlightTx = highlightTx;
this.start();
}
}
}
}
}
setHighlightingEnabled(enabled: boolean): void {
for (const scene of this.scenes) {
scene.setHighlighting(enabled);
@ -530,6 +665,24 @@ export class BlockOverviewMultiComponent implements AfterViewInit, OnDestroy, On
this.start();
}
onTxClick(cssX: number, cssY: number, keyModifier: boolean = false) {
for (const scene of this.scenes) {
if (scene) {
const x = cssX * window.devicePixelRatio;
const y = cssY * window.devicePixelRatio;
const selected = scene.getTxAt({ x, y: this.displayHeight - y });
if (selected && selected.txid) {
this.txClickEvent.emit({ tx: selected, keyModifier });
return;
}
}
}
}
onTxHover(hoverId: string) {
this.txHoverEvent.emit(hoverId);
}
getColorFunction(): ((tx: TxView) => Color) {
if (this.overrideColors) {
return this.overrideColors;

View File

@ -11,4 +11,5 @@
[animationDuration]="animationDuration"
[animationOffset]="animationOffset"
[disableSpinner]="true"
(txClickEvent)="onTxClick($event)"
></app-block-overview-multi>

View File

@ -12,6 +12,7 @@ import { BytesPipe } from '../../shared/pipes/bytes-pipe/bytes.pipe';
import { BlockOverviewMultiComponent } from '../block-overview-multi/block-overview-multi.component';
import { CacheService } from '../../services/cache.service';
import { isMempoolDelta, MempoolBlockDelta } from '../../interfaces/websocket.interface';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
function bestFitResolution(min, max, n): number {
const target = (min + max) / 2;
@ -53,7 +54,6 @@ export class EightMempoolComponent implements OnInit, OnDestroy {
queryParamsSubscription: Subscription;
graphChangeSubscription: Subscription;
blockSub: Subscription;
mempoolBlockSub: Subscription;
chainDirection: string = 'right';
poolDirection: string = 'left';
@ -178,10 +178,18 @@ export class EightMempoolComponent implements OnInit, OnDestroy {
.subscribe((network) => this.network = network);
}
onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void {
const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`);
if (!event.keyModifier) {
this.router.navigate([url]);
} else {
window.open(url, '_blank');
}
}
ngOnDestroy(): void {
this.stateService.markBlock$.next({});
this.blockSub.unsubscribe();
this.mempoolBlockSub.unsubscribe();
this.networkChangedSubscription?.unsubscribe();
this.queryParamsSubscription?.unsubscribe();
}