From 9b287336d0ce2e3adf70fe586f15583117d3fc87 Mon Sep 17 00:00:00 2001 From: Simon Lindh Date: Sun, 18 Aug 2019 17:22:16 +0300 Subject: [PATCH] Added fee distribution Pie Chart to the block inspector. --- frontend/src/app/app.module.ts | 2 + .../block-modal/block-modal.component.html | 13 +- .../block-modal/block-modal.component.ts | 46 ------ .../projected-block-modal.component.html | 13 +- .../projected-block-modal.component.ts | 47 +------ .../fee-distribution-graph.component.html | 30 ++++ .../fee-distribution-graph.component.scss | 0 .../fee-distribution-graph.component.ts | 131 ++++++++++++++++++ .../src/app/statistics/chartist.component.ts | 6 +- 9 files changed, 169 insertions(+), 119 deletions(-) create mode 100644 frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.html create mode 100644 frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.scss create mode 100644 frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.ts diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 8431e5ef6..24064cfc2 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -19,6 +19,7 @@ import { BlockchainBlocksComponent } from './blockchain-blocks/blockchain-blocks import { BlockchainProjectedBlocksComponent } from './blockchain-projected-blocks/blockchain-projected-blocks.component'; import { ApiService } from './services/api.service'; import { MasterPageComponent } from './master-page/master-page.component'; +import { FeeDistributionGraphComponent } from './fee-distribution-graph/fee-distribution-graph.component'; @NgModule({ declarations: [ @@ -34,6 +35,7 @@ import { MasterPageComponent } from './master-page/master-page.component'; BlockchainBlocksComponent, BlockchainProjectedBlocksComponent, MasterPageComponent, + FeeDistributionGraphComponent, ], imports: [ ReactiveFormsModule, diff --git a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html index f726dad7d..146e67605 100644 --- a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html +++ b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html @@ -30,16 +30,5 @@
-
- - -
- -
-
-
-
+ diff --git a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.ts b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.ts index b38874f17..48c7c9a1e 100644 --- a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.ts +++ b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.ts @@ -1,9 +1,7 @@ import { Component, OnInit, Input } from '@angular/core'; 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 * as Chartist from 'chartist'; @Component({ selector: 'app-block-modal', @@ -13,61 +11,17 @@ import * as Chartist from 'chartist'; export class BlockModalComponent implements OnInit { @Input() block: IBlock; - mempoolVsizeFeesData: any; - mempoolVsizeFeesOptions: any; conversions: any; constructor( public activeModal: NgbActiveModal, - private apiService: ApiService, private memPoolService: MemPoolService, ) { } 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$ .subscribe((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)] - }; - }); } - } diff --git a/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.html b/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.html index add57bbe9..f42bdca45 100644 --- a/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.html +++ b/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.html @@ -26,16 +26,5 @@
-
- - -
- -
-
-
-
+ diff --git a/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.ts b/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.ts index 3bf267b77..eccf770de 100644 --- a/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.ts +++ b/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.ts @@ -1,9 +1,7 @@ import { Component, OnInit, Input } from '@angular/core'; 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 * as Chartist from 'chartist'; +import { IBlock } from 'src/app/blockchain/interfaces'; @Component({ selector: 'app-projected-block-modal', @@ -14,61 +12,18 @@ export class ProjectedBlockModalComponent implements OnInit { @Input() block: IBlock; @Input() index: number; - mempoolVsizeFeesData: any; - mempoolVsizeFeesOptions: any; conversions: any; constructor( public activeModal: NgbActiveModal, - private apiService: ApiService, private memPoolService: MemPoolService, ) { } 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$ .subscribe((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)] - }; - }); } } diff --git a/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.html b/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.html new file mode 100644 index 000000000..5291bbda6 --- /dev/null +++ b/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.html @@ -0,0 +1,30 @@ +
+
+
+ + +
+
+ + + + +
+ + +
+
+
+
diff --git a/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.scss b/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.ts new file mode 100644 index 000000000..ea948f317 --- /dev/null +++ b/frontend/src/app/fee-distribution-graph/fee-distribution-graph.component.ts @@ -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] + }; + }); + } + +} diff --git a/frontend/src/app/statistics/chartist.component.ts b/frontend/src/app/statistics/chartist.component.ts index d483395e6..f37bb2a8b 100644 --- a/frontend/src/app/statistics/chartist.component.ts +++ b/frontend/src/app/statistics/chartist.component.ts @@ -496,9 +496,9 @@ Chartist.plugins.tooltip = function (options: any) { return function tooltip(chart: any) { let tooltipSelector = options.pointClass; - if (chart.constructor.name === Chartist.Bar.prototype.constructor.name) { + if (chart instanceof Chartist.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 if (chart.options.donut) { tooltipSelector = 'ct-slice-donut'; @@ -542,7 +542,7 @@ Chartist.plugins.tooltip = function (options: any) { let value = $point.getAttribute('ct:value'); 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') {