Added fee distribution Pie Chart to the block inspector.
This commit is contained in:
parent
bd19b88f11
commit
9b287336d0
@ -19,6 +19,7 @@ import { BlockchainBlocksComponent } from './blockchain-blocks/blockchain-blocks
|
|||||||
import { BlockchainProjectedBlocksComponent } from './blockchain-projected-blocks/blockchain-projected-blocks.component';
|
import { BlockchainProjectedBlocksComponent } from './blockchain-projected-blocks/blockchain-projected-blocks.component';
|
||||||
import { ApiService } from './services/api.service';
|
import { ApiService } from './services/api.service';
|
||||||
import { MasterPageComponent } from './master-page/master-page.component';
|
import { MasterPageComponent } from './master-page/master-page.component';
|
||||||
|
import { FeeDistributionGraphComponent } from './fee-distribution-graph/fee-distribution-graph.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -34,6 +35,7 @@ import { MasterPageComponent } from './master-page/master-page.component';
|
|||||||
BlockchainBlocksComponent,
|
BlockchainBlocksComponent,
|
||||||
BlockchainProjectedBlocksComponent,
|
BlockchainProjectedBlocksComponent,
|
||||||
MasterPageComponent,
|
MasterPageComponent,
|
||||||
|
FeeDistributionGraphComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
|
@ -30,16 +30,5 @@
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div style="height: 400px;" *ngIf="mempoolVsizeFeesData; else loadingFees">
|
<app-fee-distribution-graph [blockHeight]="block.height"></app-fee-distribution-graph>
|
||||||
<app-chartist
|
|
||||||
[data]="mempoolVsizeFeesData"
|
|
||||||
[type]="'Bar'"
|
|
||||||
[options]="mempoolVsizeFeesOptions">
|
|
||||||
</app-chartist>
|
|
||||||
</div>
|
|
||||||
<ng-template #loadingFees>
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="spinner-border text-light"></div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { ApiService } from '../../services/api.service';
|
|
||||||
import { IBlock } from '../../blockchain/interfaces';
|
import { IBlock } from '../../blockchain/interfaces';
|
||||||
import { MemPoolService } from '../../services/mem-pool.service';
|
import { MemPoolService } from '../../services/mem-pool.service';
|
||||||
import * as Chartist from 'chartist';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block-modal',
|
selector: 'app-block-modal',
|
||||||
@ -13,61 +11,17 @@ import * as Chartist from 'chartist';
|
|||||||
export class BlockModalComponent implements OnInit {
|
export class BlockModalComponent implements OnInit {
|
||||||
@Input() block: IBlock;
|
@Input() block: IBlock;
|
||||||
|
|
||||||
mempoolVsizeFeesData: any;
|
|
||||||
mempoolVsizeFeesOptions: any;
|
|
||||||
conversions: any;
|
conversions: any;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public activeModal: NgbActiveModal,
|
public activeModal: NgbActiveModal,
|
||||||
private apiService: ApiService,
|
|
||||||
private memPoolService: MemPoolService,
|
private memPoolService: MemPoolService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|
||||||
this.mempoolVsizeFeesOptions = {
|
|
||||||
showArea: false,
|
|
||||||
showLine: false,
|
|
||||||
fullWidth: false,
|
|
||||||
showPoint: false,
|
|
||||||
low: 0,
|
|
||||||
axisX: {
|
|
||||||
position: 'start',
|
|
||||||
showLabel: false,
|
|
||||||
offset: 0,
|
|
||||||
showGrid: false,
|
|
||||||
},
|
|
||||||
axisY: {
|
|
||||||
position: 'end',
|
|
||||||
scaleMinSpace: 40,
|
|
||||||
showGrid: false,
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
Chartist.plugins.tooltip({
|
|
||||||
tooltipOffset: {
|
|
||||||
x: 15,
|
|
||||||
y: 250
|
|
||||||
},
|
|
||||||
transformTooltipTextFnc: (value: number): any => {
|
|
||||||
return Math.ceil(value) + ' sat/vB';
|
|
||||||
},
|
|
||||||
anchorToPoint: false,
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
this.memPoolService.conversions$
|
this.memPoolService.conversions$
|
||||||
.subscribe((conversions) => {
|
.subscribe((conversions) => {
|
||||||
this.conversions = conversions;
|
this.conversions = conversions;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.apiService.listTransactionsForBlock$(this.block.height)
|
|
||||||
.subscribe((data) => {
|
|
||||||
this.mempoolVsizeFeesData = {
|
|
||||||
labels: data.map((x, i) => i),
|
|
||||||
series: [data.map((tx) => tx.fpv)]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,16 +26,5 @@
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div style="height: 400px;" *ngIf="mempoolVsizeFeesData; else loadingFees">
|
<app-fee-distribution-graph [projectedBlockIndex]="index"></app-fee-distribution-graph>
|
||||||
<app-chartist
|
|
||||||
[data]="mempoolVsizeFeesData"
|
|
||||||
[type]="'Bar'"
|
|
||||||
[options]="mempoolVsizeFeesOptions">
|
|
||||||
</app-chartist>
|
|
||||||
</div>
|
|
||||||
<ng-template #loadingFees>
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="spinner-border text-light"></div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { ApiService } from '../../services/api.service';
|
|
||||||
import { IBlock } from '../../blockchain/interfaces';
|
|
||||||
import { MemPoolService } from '../../services/mem-pool.service';
|
import { MemPoolService } from '../../services/mem-pool.service';
|
||||||
import * as Chartist from 'chartist';
|
import { IBlock } from 'src/app/blockchain/interfaces';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-projected-block-modal',
|
selector: 'app-projected-block-modal',
|
||||||
@ -14,61 +12,18 @@ export class ProjectedBlockModalComponent implements OnInit {
|
|||||||
@Input() block: IBlock;
|
@Input() block: IBlock;
|
||||||
@Input() index: number;
|
@Input() index: number;
|
||||||
|
|
||||||
mempoolVsizeFeesData: any;
|
|
||||||
mempoolVsizeFeesOptions: any;
|
|
||||||
conversions: any;
|
conversions: any;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public activeModal: NgbActiveModal,
|
public activeModal: NgbActiveModal,
|
||||||
private apiService: ApiService,
|
|
||||||
private memPoolService: MemPoolService,
|
private memPoolService: MemPoolService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|
||||||
this.mempoolVsizeFeesOptions = {
|
|
||||||
showArea: false,
|
|
||||||
showLine: false,
|
|
||||||
fullWidth: false,
|
|
||||||
showPoint: false,
|
|
||||||
low: 0,
|
|
||||||
axisX: {
|
|
||||||
position: 'start',
|
|
||||||
showLabel: false,
|
|
||||||
offset: 0,
|
|
||||||
showGrid: false,
|
|
||||||
},
|
|
||||||
axisY: {
|
|
||||||
position: 'end',
|
|
||||||
scaleMinSpace: 40,
|
|
||||||
showGrid: false,
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
Chartist.plugins.tooltip({
|
|
||||||
tooltipOffset: {
|
|
||||||
x: 15,
|
|
||||||
y: 250
|
|
||||||
},
|
|
||||||
transformTooltipTextFnc: (value: number): any => {
|
|
||||||
return Math.ceil(value) + ' sat/vB';
|
|
||||||
},
|
|
||||||
anchorToPoint: false,
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
this.memPoolService.conversions$
|
this.memPoolService.conversions$
|
||||||
.subscribe((conversions) => {
|
.subscribe((conversions) => {
|
||||||
this.conversions = conversions;
|
this.conversions = conversions;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.apiService.listTransactionsForProjectedBlock$(this.index)
|
|
||||||
.subscribe((data) => {
|
|
||||||
this.mempoolVsizeFeesData = {
|
|
||||||
labels: data.map((x, i) => i),
|
|
||||||
series: [data.map((tx) => tx.fpv)]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<div style="height: 400px;" *ngIf="mempoolVsizeFeesData; else loadingFees">
|
||||||
|
<form [formGroup]="radioGroupForm" style="position: absolute;">
|
||||||
|
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="model">
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
|
<input ngbButton type="radio" value="line"> Line
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
|
<input ngbButton type="radio" value="pie"> Pie
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<app-chartist
|
||||||
|
*ngIf="radioGroupForm.get('model')?.value === 'pie'"
|
||||||
|
[data]="mempoolVsizeFeesPieData"
|
||||||
|
[type]="'Pie'"
|
||||||
|
[options]="mempoolVsizeFeesPieOptions">
|
||||||
|
</app-chartist>
|
||||||
|
<app-chartist
|
||||||
|
*ngIf="radioGroupForm.get('model')?.value === 'line'"
|
||||||
|
[data]="mempoolVsizeFeesData"
|
||||||
|
[type]="'Bar'"
|
||||||
|
[options]="mempoolVsizeFeesOptions">
|
||||||
|
</app-chartist>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #loadingFees>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="spinner-border text-light"></div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
@ -0,0 +1,131 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import * as Chartist from 'chartist';
|
||||||
|
import { ApiService } from '../services/api.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-fee-distribution-graph',
|
||||||
|
templateUrl: './fee-distribution-graph.component.html',
|
||||||
|
styleUrls: ['./fee-distribution-graph.component.scss']
|
||||||
|
})
|
||||||
|
export class FeeDistributionGraphComponent implements OnInit {
|
||||||
|
@Input() projectedBlockIndex: number;
|
||||||
|
@Input() blockHeight: number;
|
||||||
|
|
||||||
|
mempoolVsizeFeesData: any;
|
||||||
|
mempoolVsizeFeesOptions: any;
|
||||||
|
|
||||||
|
mempoolVsizeFeesPieData: any;
|
||||||
|
mempoolVsizeFeesPieOptions: any;
|
||||||
|
|
||||||
|
feeLevels = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200,
|
||||||
|
250, 300, 350, 400, 500];
|
||||||
|
|
||||||
|
radioGroupForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private apiService: ApiService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.radioGroupForm = this.formBuilder.group({
|
||||||
|
model: ['line'],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.mempoolVsizeFeesOptions = {
|
||||||
|
showArea: false,
|
||||||
|
showLine: false,
|
||||||
|
fullWidth: false,
|
||||||
|
showPoint: false,
|
||||||
|
low: 0,
|
||||||
|
axisX: {
|
||||||
|
position: 'start',
|
||||||
|
showLabel: false,
|
||||||
|
offset: 0,
|
||||||
|
showGrid: false,
|
||||||
|
},
|
||||||
|
axisY: {
|
||||||
|
position: 'end',
|
||||||
|
scaleMinSpace: 40,
|
||||||
|
showGrid: false,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
Chartist.plugins.tooltip({
|
||||||
|
tooltipOffset: {
|
||||||
|
x: 15,
|
||||||
|
y: 250
|
||||||
|
},
|
||||||
|
transformTooltipTextFnc: (value: number): any => {
|
||||||
|
return Math.ceil(value) + ' sat/vB';
|
||||||
|
},
|
||||||
|
anchorToPoint: false,
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.mempoolVsizeFeesPieOptions = {
|
||||||
|
showLabel: false,
|
||||||
|
plugins: [
|
||||||
|
Chartist.plugins.tooltip({
|
||||||
|
tooltipOffset: {
|
||||||
|
x: 15,
|
||||||
|
y: 250
|
||||||
|
},
|
||||||
|
transformTooltipTextFnc: (value: string, seriesName: string): any => {
|
||||||
|
const index = parseInt(seriesName.split(' ')[2].split('-')[1], 10);
|
||||||
|
const intValue = parseInt(value, 10);
|
||||||
|
const result = Math.ceil(intValue) + ' tx @ ' + this.feeLevels[index] +
|
||||||
|
(this.feeLevels[index + 1] ? '-' + this.feeLevels[index + 1] : '+' ) + ' sat/vB';
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
anchorToPoint: false,
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let sub;
|
||||||
|
if (this.blockHeight) {
|
||||||
|
sub = this.apiService.listTransactionsForBlock$(this.blockHeight);
|
||||||
|
} else {
|
||||||
|
sub = this.apiService.listTransactionsForProjectedBlock$(this.projectedBlockIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub.subscribe((data) => {
|
||||||
|
const fees = data.map((tx) => tx.fpv);
|
||||||
|
|
||||||
|
const series = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.feeLevels.length; i++) {
|
||||||
|
let total = 0;
|
||||||
|
for (let j = 0; j < fees.length; j++) {
|
||||||
|
if (i === this.feeLevels.length - 1) {
|
||||||
|
if (fees[j] >= this.feeLevels[i]) {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
} else if (fees[j] >= this.feeLevels[i] && fees[j] < this.feeLevels[i + 1]) {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
series.push(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mempoolVsizeFeesPieData = {
|
||||||
|
series: series.map((d, index: number) => {
|
||||||
|
return {
|
||||||
|
value: d,
|
||||||
|
className: 'ct-series-' + Chartist.alphaNumerate(index) + ' index-' + index
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
labels: data.map((x, i) => i),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.mempoolVsizeFeesData = {
|
||||||
|
labels: data.map((x, i) => i),
|
||||||
|
series: [fees]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -496,9 +496,9 @@ Chartist.plugins.tooltip = function (options: any) {
|
|||||||
|
|
||||||
return function tooltip(chart: any) {
|
return function tooltip(chart: any) {
|
||||||
let tooltipSelector = options.pointClass;
|
let tooltipSelector = options.pointClass;
|
||||||
if (chart.constructor.name === Chartist.Bar.prototype.constructor.name) {
|
if (chart instanceof Chartist.Bar) {
|
||||||
tooltipSelector = 'ct-bar';
|
tooltipSelector = 'ct-bar';
|
||||||
} else if (chart.constructor.name === Chartist.Pie.prototype.constructor.name) {
|
} else if (chart instanceof Chartist.Pie) {
|
||||||
// Added support for donut graph
|
// Added support for donut graph
|
||||||
if (chart.options.donut) {
|
if (chart.options.donut) {
|
||||||
tooltipSelector = 'ct-slice-donut';
|
tooltipSelector = 'ct-slice-donut';
|
||||||
@ -542,7 +542,7 @@ Chartist.plugins.tooltip = function (options: any) {
|
|||||||
let value = $point.getAttribute('ct:value');
|
let value = $point.getAttribute('ct:value');
|
||||||
|
|
||||||
if (options.transformTooltipTextFnc && typeof options.transformTooltipTextFnc === 'function') {
|
if (options.transformTooltipTextFnc && typeof options.transformTooltipTextFnc === 'function') {
|
||||||
value = options.transformTooltipTextFnc(value);
|
value = options.transformTooltipTextFnc(value, $point.parentNode.getAttribute('class'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.tooltipFnc && typeof options.tooltipFnc === 'function') {
|
if (options.tooltipFnc && typeof options.tooltipFnc === 'function') {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user