eight blocks
This commit is contained in:
parent
108d1762d6
commit
ec8fc53dcb
@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { AppPreloadingStrategy } from './app.preloading-strategy'
|
||||
import { BlockViewComponent } from './components/block-view/block-view.component';
|
||||
import { EightBlocksComponent } from './components/eight-blocks/eight-blocks.component';
|
||||
import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
|
||||
import { ClockComponent } from './components/clock/clock.component';
|
||||
import { StatusViewComponent } from './components/status-view/status-view.component';
|
||||
@ -124,6 +125,10 @@ let routes: Routes = [
|
||||
path: 'view/mempool-block/:index',
|
||||
component: MempoolBlockViewComponent,
|
||||
},
|
||||
{
|
||||
path: 'eight-blocks',
|
||||
component: EightBlocksComponent,
|
||||
},
|
||||
{
|
||||
path: 'status',
|
||||
data: { networks: ['bitcoin', 'liquid'] },
|
||||
|
@ -20,6 +20,8 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||
@Input() blockLimit: number;
|
||||
@Input() orientation = 'left';
|
||||
@Input() flip = true;
|
||||
@Input() animationDuration: number = 1000;
|
||||
@Input() animationOffset: number | null = null;
|
||||
@Input() disableSpinner = false;
|
||||
@Input() mirrorTxid: string | void;
|
||||
@Input() unavailable: boolean = false;
|
||||
@ -141,9 +143,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||
}
|
||||
}
|
||||
|
||||
replace(transactions: TransactionStripped[], direction: string, sort: boolean = true): void {
|
||||
replace(transactions: TransactionStripped[], direction: string, sort: boolean = true, startTime?: number): void {
|
||||
if (this.scene) {
|
||||
this.scene.replace(transactions || [], direction, sort);
|
||||
this.scene.replace(transactions || [], direction, sort, startTime);
|
||||
this.start();
|
||||
this.updateSearchHighlight();
|
||||
}
|
||||
@ -226,7 +228,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||
} else {
|
||||
this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution,
|
||||
blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray,
|
||||
highlighting: this.auditHighlighting });
|
||||
highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset });
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,9 @@ export default class BlockScene {
|
||||
txs: { [key: string]: TxView };
|
||||
orientation: string;
|
||||
flip: boolean;
|
||||
animationDuration: number = 1000;
|
||||
configAnimationOffset: number | null;
|
||||
animationOffset: number;
|
||||
highlightingEnabled: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
@ -23,11 +26,11 @@ export default class BlockScene {
|
||||
animateUntil = 0;
|
||||
dirty: boolean;
|
||||
|
||||
constructor({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting }:
|
||||
{ width: number, height: number, resolution: number, blockLimit: number,
|
||||
constructor({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting }:
|
||||
{ width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number,
|
||||
orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean }
|
||||
) {
|
||||
this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting });
|
||||
this.init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting });
|
||||
}
|
||||
|
||||
resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void {
|
||||
@ -36,6 +39,7 @@ export default class BlockScene {
|
||||
this.gridSize = this.width / this.gridWidth;
|
||||
this.unitPadding = Math.max(1, Math.floor(this.gridSize / 5));
|
||||
this.unitWidth = this.gridSize - (this.unitPadding * 2);
|
||||
this.animationOffset = this.configAnimationOffset == null ? (this.width * 1.4) : this.configAnimationOffset;
|
||||
|
||||
this.dirty = true;
|
||||
if (this.initialised && this.scene) {
|
||||
@ -90,8 +94,8 @@ export default class BlockScene {
|
||||
}
|
||||
|
||||
// Animate new block entering scene
|
||||
enter(txs: TransactionStripped[], direction) {
|
||||
this.replace(txs, direction);
|
||||
enter(txs: TransactionStripped[], direction, startTime?: number) {
|
||||
this.replace(txs, direction, false, startTime);
|
||||
}
|
||||
|
||||
// Animate block leaving scene
|
||||
@ -108,8 +112,7 @@ export default class BlockScene {
|
||||
}
|
||||
|
||||
// Reset layout and replace with new set of transactions
|
||||
replace(txs: TransactionStripped[], direction: string = 'left', sort: boolean = true): void {
|
||||
const startTime = performance.now();
|
||||
replace(txs: TransactionStripped[], direction: string = 'left', sort: boolean = true, startTime: number = performance.now()): void {
|
||||
const nextIds = {};
|
||||
const remove = [];
|
||||
txs.forEach(tx => {
|
||||
@ -133,7 +136,7 @@ export default class BlockScene {
|
||||
removed.forEach(tx => {
|
||||
tx.destroy();
|
||||
});
|
||||
}, 1000);
|
||||
}, (startTime - performance.now()) + this.animationDuration + 1000);
|
||||
|
||||
this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight });
|
||||
|
||||
@ -147,7 +150,7 @@ export default class BlockScene {
|
||||
});
|
||||
}
|
||||
|
||||
this.updateAll(startTime, 200, direction);
|
||||
this.updateAll(startTime, 50, direction);
|
||||
}
|
||||
|
||||
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
|
||||
@ -214,10 +217,13 @@ export default class BlockScene {
|
||||
this.animateUntil = Math.max(this.animateUntil, tx.setHighlight(value));
|
||||
}
|
||||
|
||||
private init({ width, height, resolution, blockLimit, orientation, flip, vertexArray, highlighting }:
|
||||
{ width: number, height: number, resolution: number, blockLimit: number,
|
||||
private init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting }:
|
||||
{ width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number,
|
||||
orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean }
|
||||
): void {
|
||||
this.animationDuration = animationDuration || 1000;
|
||||
this.configAnimationOffset = animationOffset;
|
||||
this.animationOffset = this.configAnimationOffset == null ? (this.width * 1.4) : this.configAnimationOffset;
|
||||
this.orientation = orientation;
|
||||
this.flip = flip;
|
||||
this.vertexArray = vertexArray;
|
||||
@ -261,8 +267,8 @@ export default class BlockScene {
|
||||
this.applyTxUpdate(tx, {
|
||||
display: {
|
||||
position: {
|
||||
x: tx.screenPosition.x + (direction === 'right' ? -this.width : (direction === 'left' ? this.width : 0)) * 1.4,
|
||||
y: tx.screenPosition.y + (direction === 'up' ? -this.height : (direction === 'down' ? this.height : 0)) * 1.4,
|
||||
x: tx.screenPosition.x + (direction === 'right' ? -this.width - this.animationOffset : (direction === 'left' ? this.width + this.animationOffset : 0)),
|
||||
y: tx.screenPosition.y + (direction === 'up' ? -this.height - this.animationOffset : (direction === 'down' ? this.height + this.animationOffset : 0)),
|
||||
s: tx.screenPosition.s
|
||||
},
|
||||
color: txColor,
|
||||
@ -275,7 +281,7 @@ export default class BlockScene {
|
||||
position: tx.screenPosition,
|
||||
color: txColor
|
||||
},
|
||||
duration: animate ? 1000 : 1,
|
||||
duration: animate ? this.animationDuration : 1,
|
||||
start: startTime,
|
||||
delay: animate ? delay : 0,
|
||||
});
|
||||
@ -284,8 +290,8 @@ export default class BlockScene {
|
||||
display: {
|
||||
position: tx.screenPosition
|
||||
},
|
||||
duration: animate ? 1000 : 0,
|
||||
minDuration: animate ? 500 : 0,
|
||||
duration: animate ? this.animationDuration : 0,
|
||||
minDuration: animate ? (this.animationDuration / 2) : 0,
|
||||
start: startTime,
|
||||
delay: animate ? delay : 0,
|
||||
adjust: animate
|
||||
@ -322,11 +328,11 @@ export default class BlockScene {
|
||||
this.applyTxUpdate(tx, {
|
||||
display: {
|
||||
position: {
|
||||
x: tx.screenPosition.x + (direction === 'right' ? this.width : (direction === 'left' ? -this.width : 0)) * 1.4,
|
||||
y: tx.screenPosition.y + (direction === 'up' ? this.height : (direction === 'down' ? -this.height : 0)) * 1.4,
|
||||
x: tx.screenPosition.x + (direction === 'right' ? this.width + this.animationOffset : (direction === 'left' ? -this.width - this.animationOffset : 0)),
|
||||
y: tx.screenPosition.y + (direction === 'up' ? this.height + this.animationOffset : (direction === 'down' ? -this.height - this.animationOffset : 0)),
|
||||
}
|
||||
},
|
||||
duration: 1000,
|
||||
duration: this.animationDuration,
|
||||
start: startTime,
|
||||
delay: 50
|
||||
});
|
||||
|
@ -0,0 +1,27 @@
|
||||
<div class="blocks" [class.wrap]="wrapBlocks">
|
||||
<ng-container *ngFor="let i of [0,1,2,3,4,5,6,7]">
|
||||
<div class="block-wrapper" [style]="wrapperStyle">
|
||||
<div class="block-container" [style]="containerStyle">
|
||||
<app-block-overview-graph
|
||||
#blockGraph
|
||||
[isLoading]="false"
|
||||
[resolution]="resolution"
|
||||
[blockLimit]="stateService.blockVSize"
|
||||
[orientation]="'top'"
|
||||
[flip]="false"
|
||||
[animationDuration]="animationDuration"
|
||||
[animationOffset]="animationOffset"
|
||||
[disableSpinner]="true"
|
||||
(txClickEvent)="onTxClick($event)"
|
||||
></app-block-overview-graph>
|
||||
<div *ngIf="showInfo && blockInfo[i]" class="info" @infoChange>
|
||||
<h1>{{ blockInfo[i].height }}</h1>
|
||||
<p class="hash">{{ blockInfo[i].hash }}</p>
|
||||
<h2>{{ blockInfo[i].time }}</h2>
|
||||
<h2>{{ blockInfo[i].count }}</h2>
|
||||
<h2>{{ blockInfo[i].size }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
@ -0,0 +1,50 @@
|
||||
.blocks {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 100vw;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: start;
|
||||
align-items: start;
|
||||
align-content: start;
|
||||
|
||||
&.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.block-wrapper {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
--block-width: 1080px;
|
||||
|
||||
.info {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
right: 10%;
|
||||
bottom: 10%;
|
||||
height: 80%;
|
||||
width: 80%;
|
||||
overflow: hidden;
|
||||
font-size: calc(var(--block-width) * 0.04);
|
||||
|
||||
h1 {
|
||||
font-size: 4em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2.5em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
.hash {
|
||||
font-family: monospace;
|
||||
word-wrap: break-word;
|
||||
font-size: 1em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChildren, QueryList } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { catchError, startWith } from 'rxjs/operators';
|
||||
import { Subject, Subscription, of } from 'rxjs';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { WebsocketService } from '../../services/websocket.service';
|
||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||
import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { BlockOverviewGraphComponent } from '../block-overview-graph/block-overview-graph.component';
|
||||
import { detectWebGL } from '../../shared/graphs.utils';
|
||||
import { animate, style, transition, trigger } from '@angular/animations';
|
||||
import { BytesPipe } from '../../shared/pipes/bytes-pipe/bytes.pipe';
|
||||
|
||||
function bestFitResolution(min, max, n): number {
|
||||
const target = (min + max) / 2;
|
||||
let bestScore = Infinity;
|
||||
let best = null;
|
||||
for (let i = min; i <= max; i++) {
|
||||
const remainder = (n % i);
|
||||
if (remainder < bestScore || (remainder === bestScore && (Math.abs(i - target) < Math.abs(best - target)))) {
|
||||
bestScore = remainder;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-eight-blocks',
|
||||
templateUrl: './eight-blocks.component.html',
|
||||
styleUrls: ['./eight-blocks.component.scss'],
|
||||
animations: [
|
||||
trigger('infoChange', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0 }),
|
||||
animate('1000ms', style({ opacity: 1 })),
|
||||
]),
|
||||
transition(':leave', [
|
||||
animate('1000ms 500ms', style({ opacity: 0 }))
|
||||
])
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class EightBlocksComponent implements OnInit, OnDestroy {
|
||||
network = '';
|
||||
latestBlocks: BlockExtended[] = [];
|
||||
isLoadingTransactions = true;
|
||||
strippedTransactions: { [height: number]: TransactionStripped[] } = {};
|
||||
webGlEnabled = true;
|
||||
hoverTx: string | null = null;
|
||||
|
||||
blocksSubscription: Subscription;
|
||||
cacheBlocksSubscription: Subscription;
|
||||
networkChangedSubscription: Subscription;
|
||||
queryParamsSubscription: Subscription;
|
||||
graphChangeSubscription: Subscription;
|
||||
|
||||
autofit: boolean = false;
|
||||
padding: number = 0;
|
||||
wrapBlocks: boolean = false;
|
||||
blockWidth: number = 1080;
|
||||
animationDuration: number = 2000;
|
||||
animationOffset: number = 0;
|
||||
stagger: number = 0;
|
||||
testing: boolean = true;
|
||||
testHeight: number = 800000;
|
||||
testShiftTimeout: number;
|
||||
|
||||
showInfo: boolean = true;
|
||||
blockInfo: { [key: string]: string}[] = [];
|
||||
|
||||
wrapperStyle = {
|
||||
'--block-width': '1080px',
|
||||
width: '1080px',
|
||||
maxWidth: '1080px',
|
||||
padding: '',
|
||||
};
|
||||
containerStyle = {};
|
||||
resolution: number = 86;
|
||||
|
||||
@ViewChildren('blockGraph') blockGraphs: QueryList<BlockOverviewGraphComponent>;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
public stateService: StateService,
|
||||
private websocketService: WebsocketService,
|
||||
private apiService: ApiService,
|
||||
private bytesPipe: BytesPipe,
|
||||
) {
|
||||
this.webGlEnabled = detectWebGL();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.websocketService.want(['blocks']);
|
||||
this.network = this.stateService.network;
|
||||
|
||||
this.blocksSubscription = this.stateService.blocks$
|
||||
.subscribe((blocks) => {
|
||||
this.handleNewBlock(blocks);
|
||||
});
|
||||
|
||||
this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {
|
||||
this.autofit = params.autofit === 'true';
|
||||
this.padding = Number.isInteger(Number(params.padding)) ? Number(params.padding) : 0;
|
||||
this.blockWidth = Number.isInteger(Number(params.blockWidth)) ? Number(params.blockWidth) : 1080;
|
||||
this.wrapBlocks = params.wrap === 'true';
|
||||
this.stagger = Number.isInteger(Number(params.stagger)) ? Number(params.stagger) : 0;
|
||||
this.animationDuration = Number.isInteger(Number(params.animationDuration)) ? Number(params.animationDuration) : 2000;
|
||||
this.animationOffset = this.padding * 2;
|
||||
|
||||
if (this.autofit) {
|
||||
this.resolution = bestFitResolution(76, 96, this.blockWidth - this.padding * 2);
|
||||
} else {
|
||||
this.resolution = 86;
|
||||
}
|
||||
|
||||
this.wrapperStyle = {
|
||||
'--block-width': this.blockWidth + 'px',
|
||||
width: this.blockWidth + 'px',
|
||||
maxWidth: this.blockWidth + 'px',
|
||||
padding: (this.padding || 0) +'px 0px',
|
||||
};
|
||||
|
||||
if (params.test === 'true') {
|
||||
this.blocksSubscription.unsubscribe();
|
||||
this.blocksSubscription = (new Subject<BlockExtended[]>()).subscribe((blocks) => {
|
||||
this.handleNewBlock(blocks);
|
||||
});
|
||||
this.shiftTestBlocks();
|
||||
}
|
||||
});
|
||||
|
||||
this.setupBlockGraphs();
|
||||
|
||||
this.networkChangedSubscription = this.stateService.networkChanged$
|
||||
.subscribe((network) => this.network = network);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.graphChangeSubscription = this.blockGraphs.changes.pipe(startWith(null)).subscribe(() => {
|
||||
this.setupBlockGraphs();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.stateService.markBlock$.next({});
|
||||
this.blocksSubscription?.unsubscribe();
|
||||
this.cacheBlocksSubscription?.unsubscribe();
|
||||
this.networkChangedSubscription?.unsubscribe();
|
||||
this.queryParamsSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
shiftTestBlocks(): void {
|
||||
const sub = this.apiService.getBlocks$(this.testHeight).subscribe(result => {
|
||||
sub.unsubscribe();
|
||||
this.handleNewBlock(result);
|
||||
this.testHeight++;
|
||||
clearTimeout(this.testShiftTimeout);
|
||||
this.testShiftTimeout = window.setTimeout(() => { this.shiftTestBlocks(); }, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
async handleNewBlock(blocks: BlockExtended[]): Promise<void> {
|
||||
const readyPromises: Promise<TransactionStripped[]>[] = [];
|
||||
const previousBlocks = this.latestBlocks;
|
||||
const newHeights = {};
|
||||
this.latestBlocks = blocks;
|
||||
for (const block of blocks) {
|
||||
newHeights[block.height] = true;
|
||||
if (!this.strippedTransactions[block.height]) {
|
||||
readyPromises.push(new Promise((resolve) => {
|
||||
const subscription = this.apiService.getStrippedBlockTransactions$(block.id).pipe(
|
||||
catchError(() => {
|
||||
return of([]);
|
||||
}),
|
||||
).subscribe((transactions) => {
|
||||
this.strippedTransactions[block.height] = transactions;
|
||||
subscription.unsubscribe();
|
||||
resolve(transactions);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
await Promise.allSettled(readyPromises);
|
||||
this.updateBlockGraphs(blocks);
|
||||
|
||||
// free up old transactions
|
||||
previousBlocks.forEach(block => {
|
||||
if (!newHeights[block.height]) {
|
||||
delete this.strippedTransactions[block.height];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateBlockGraphs(blocks): void {
|
||||
const startTime = performance.now() + 1000 - (this.stagger < 0 ? this.stagger * 8 : 0);
|
||||
if (this.blockGraphs) {
|
||||
this.blockGraphs.forEach((graph, index) => {
|
||||
graph.replace(this.strippedTransactions[blocks?.[index]?.height] || [], 'right', false, startTime + (this.stagger * index));
|
||||
});
|
||||
}
|
||||
this.showInfo = false;
|
||||
setTimeout(() => {
|
||||
this.blockInfo = blocks.map(block => {
|
||||
return {
|
||||
height: `${block.height}`,
|
||||
hash: block.id,
|
||||
time: (new Date(block.timestamp * 1000)).toLocaleTimeString(),
|
||||
count: `${block.tx_count} txs`,
|
||||
size: `${this.bytesPipe.transform(block.size, 2, 'B', 'MB', true)}`,
|
||||
};
|
||||
});
|
||||
this.showInfo = true;
|
||||
}, 1600); // Should match the animation time.
|
||||
}
|
||||
|
||||
setupBlockGraphs(): void {
|
||||
if (this.blockGraphs) {
|
||||
this.blockGraphs.forEach((graph, index) => {
|
||||
graph.destroy();
|
||||
graph.setup(this.strippedTransactions[this.latestBlocks?.[index]?.height] || []);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
onTxHover(txid: string): void {
|
||||
if (txid && txid.length) {
|
||||
this.hoverTx = txid;
|
||||
} else {
|
||||
this.hoverTx = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -237,7 +237,7 @@
|
||||
<div class="card-text" *ngIf="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value; else loadingbig">
|
||||
<div class="progress">
|
||||
<div class="progress-bar {{ mempoolInfoData.value.mempoolSizeProgress }}" role="progressbar" [ngStyle]="{'width': (mempoolInfoData.value.memPoolInfo.usage / mempoolInfoData.value.memPoolInfo.maxmempool * 100) + '%' }"> </div>
|
||||
<div class="progress-text">‎<span [innerHTML]="mempoolInfoData.value.memPoolInfo.usage | bytes : 2 : 'B' : null : 3"></span> / <span [innerHTML]="mempoolInfoData.value.memPoolInfo.maxmempool | bytes"></span></div>
|
||||
<div class="progress-text">‎<span [innerHTML]="mempoolInfoData.value.memPoolInfo.usage | bytes : 2 : 'B' : null : false : 3"></span> / <span [innerHTML]="mempoolInfoData.value.memPoolInfo.maxmempool | bytes"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -17,7 +17,7 @@ export class BytesPipe implements PipeTransform {
|
||||
'TB': {max: Number.MAX_SAFE_INTEGER, prev: 'GB'}
|
||||
};
|
||||
|
||||
transform(input: any, decimal: number = 0, from: ByteUnit = 'B', to?: ByteUnit, sigfigs?: number): any {
|
||||
transform(input: any, decimal: number = 0, from: ByteUnit = 'B', to?: ByteUnit, plaintext = false, sigfigs?: number): any {
|
||||
|
||||
if (!(isNumberFinite(input) &&
|
||||
isNumberFinite(decimal) &&
|
||||
@ -42,7 +42,7 @@ export class BytesPipe implements PipeTransform {
|
||||
|
||||
const result = numberFormat(BytesPipe.calculateResult(format, bytes));
|
||||
|
||||
return BytesPipe.formatResult(result, to);
|
||||
return BytesPipe.formatResult(result, to, plaintext);
|
||||
}
|
||||
|
||||
for (const key in BytesPipe.formats) {
|
||||
@ -51,13 +51,17 @@ export class BytesPipe implements PipeTransform {
|
||||
|
||||
const result = numberFormat(BytesPipe.calculateResult(format, bytes));
|
||||
|
||||
return BytesPipe.formatResult(result, key);
|
||||
return BytesPipe.formatResult(result, key, plaintext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static formatResult(result: string, unit: string): string {
|
||||
return `${result} <span class="symbol">${unit}</span>`;
|
||||
static formatResult(result: string, unit: string, plaintext): string {
|
||||
if (plaintext) {
|
||||
return `${result} ${unit}`;
|
||||
} else {
|
||||
return `${result} <span class="symbol">${unit}</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
static calculateResult(format: { max: number, prev?: ByteUnit }, bytes: number) {
|
||||
|
@ -87,6 +87,7 @@ import { AccelerateFeeGraphComponent } from '../components/accelerate-preview/ac
|
||||
import { MempoolErrorComponent } from './components/mempool-error/mempool-error.component';
|
||||
|
||||
import { BlockViewComponent } from '../components/block-view/block-view.component';
|
||||
import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component';
|
||||
import { MempoolBlockViewComponent } from '../components/mempool-block-view/mempool-block-view.component';
|
||||
import { MempoolBlockOverviewComponent } from '../components/mempool-block-overview/mempool-block-overview.component';
|
||||
import { ClockchainComponent } from '../components/clockchain/clockchain.component';
|
||||
@ -126,6 +127,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
||||
ColoredPriceDirective,
|
||||
BlockchainComponent,
|
||||
BlockViewComponent,
|
||||
EightBlocksComponent,
|
||||
MempoolBlockViewComponent,
|
||||
MempoolBlocksComponent,
|
||||
BlockchainBlocksComponent,
|
||||
@ -179,6 +181,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
||||
CalculatorComponent,
|
||||
BitcoinsatoshisPipe,
|
||||
BlockViewComponent,
|
||||
EightBlocksComponent,
|
||||
MempoolBlockViewComponent,
|
||||
MempoolBlockOverviewComponent,
|
||||
ClockchainComponent,
|
||||
@ -202,6 +205,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
||||
FontAwesomeModule,
|
||||
],
|
||||
providers: [
|
||||
BytesPipe,
|
||||
VbytesPipe,
|
||||
WuBytesPipe,
|
||||
RelativeUrlPipe,
|
||||
|
Loading…
x
Reference in New Issue
Block a user