diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 729a650f7..de67559b3 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -47,7 +47,7 @@ import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; import { FeesBoxComponent } from './components/fees-box/fees-box.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; -import { faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, +import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons'; import { ApiDocsComponent } from './components/api-docs/api-docs.component'; import { CodeTemplateComponent } from './components/api-docs/code-template.component'; @@ -140,6 +140,7 @@ export class AppModule { library.addIcons(faLink); library.addIcons(faBolt); library.addIcons(faTint); + library.addIcons(faFilter); library.addIcons(faAngleDown); library.addIcons(faAngleUp); library.addIcons(faExchangeAlt); diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts index c02e8d3f7..43f652fad 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -17,6 +17,7 @@ import { feeLevels, chartColors } from 'src/app/app.constants'; export class MempoolGraphComponent implements OnInit, OnChanges { @Input() data: any[]; @Input() limitFee = 350; + @Input() limitFilterFee = 1; @Input() height: number | string = 200; @Input() top: number | string = 20; @Input() right: number | string = 10; @@ -45,19 +46,6 @@ export class MempoolGraphComponent implements OnInit, OnChanges { ngOnInit(): void { this.inverted = this.storageService.getValue('inverted-graph') === 'true'; - for (let i = 0; i < feeLevels.length; i++) { - if (feeLevels[i] === this.limitFee) { - this.feeLimitIndex = i; - } - if (feeLevels[i] <= this.limitFee) { - if (i === 0) { - this.feeLevelsOrdered.push('0 - 1'); - } else { - this.feeLevelsOrdered.push(`${feeLevels[i - 1]} - ${feeLevels[i]}`); - } - } - } - this.chartColorsOrdered = chartColors.slice(0, this.feeLevelsOrdered.length); this.mountFeeChart(); } @@ -68,9 +56,12 @@ export class MempoolGraphComponent implements OnInit, OnChanges { } onChartReady(myChart: any) { - myChart.getZr().on('mousemove', e => { - if (e.target !== undefined) { - this.hoverIndexSerie = e.target.parent.parent.__ecComponentInfo.index; + myChart.getZr().on('mousemove', (e: any) => { + if (e.target !== undefined && + e.target.parent !== undefined && + e.target.parent.parent !== null && + e.target.parent.parent.__ecComponentInfo !== undefined) { + this.hoverIndexSerie = e.target.parent.parent.__ecComponentInfo.index; } }); } @@ -106,10 +97,11 @@ export class MempoolGraphComponent implements OnInit, OnChanges { } mountFeeChart() { + this.orderLevels(); const { labels, series } = this.mempoolVsizeFeesData; const seriesGraph = series.map((value: Array, index: number) => { - if (index <= this.feeLimitIndex){ + if (index >= this.feeLimitIndex){ return { name: this.feeLevelsOrdered[index], type: 'line', @@ -175,85 +167,81 @@ export class MempoolGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { - const colorSpan = (index: any) => ` - - ${this.feeLevelsOrdered[index]} - `; - const totals = (values: any) => { - let totalValueTemp = 0; - const totalValueArrayTemp = []; - const valuesInverted = this.inverted ? values : [...values].reverse(); - for (const item of valuesInverted) { - totalValueTemp += item.value; - totalValueArrayTemp.push(totalValueTemp); - } - return { - totalValue: totalValueTemp, - totalValueArray: totalValueArrayTemp.reverse(), - valuesOrdered: this.inverted ? [...values].reverse() : values, - }; - }; - const { totalValue, totalValueArray, valuesOrdered } = totals(params); - const title = `
- ${params[0].axisValue} - - ${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)} - -
`; + const { totalValue, totalValueArray } = this.getTotalValues(params); const itemFormatted = []; let totalParcial = 0; let progressPercentageText = ''; - params.map((item: any, index: number) => { + const items = this.inverted ? [...params].reverse() : params; + items.map((item: any, index: number) => { totalParcial += item.value; let progressPercentage = 0; let progressPercentageSum = 0; - if (index <= this.feeLimitIndex) { - progressPercentage = (item.value / totalValue) * 100; - progressPercentageSum = (totalValueArray[index] / totalValue) * 100; - let activeItemClass = ''; - const hoverActive = (this.inverted) ? Math.abs(item.seriesIndex - params.length + 1) : item.seriesIndex; - if (this.hoverIndexSerie === hoverActive) { - progressPercentageText = `
- - ${formatNumber(progressPercentage, this.locale, '1.2-2')} - % + progressPercentage = (item.value / totalValue) * 100; + progressPercentageSum = (totalValueArray[index] / totalValue) * 100; + let activeItemClass = ''; + let hoverActive: number; + if (this.inverted) { + hoverActive = Math.abs(this.feeLevelsOrdered.length - item.seriesIndex - this.feeLevelsOrdered.length); + } else { + hoverActive = item.seriesIndex; + } + if (this.hoverIndexSerie === hoverActive) { + progressPercentageText = `
+ + ${formatNumber(progressPercentage, this.locale, '1.2-2')} + % + + + ${this.vbytesPipe.transform(totalParcial, 2, 'vB', 'MvB', false)} + +
+ + - - ${this.vbytesPipe.transform(totalParcial, 2, 'vB', 'MvB', false)} - -
- - - -
-
`; - activeItemClass = 'active'; - } - itemFormatted.push(` +
+
`; + activeItemClass = 'active'; + } + itemFormatted.push(` - ${colorSpan(item.seriesIndex)} - - + - ${this.vbytesPipe.transform(valuesOrdered[item.seriesIndex].value, 2, 'vB', 'MvB', false)} + ${this.inverted ? this.feeLevelsOrdered[index] : item.seriesName} - ${this.vbytesPipe.transform(totalValueArray[item.seriesIndex], 2, 'vB', 'MvB', false)} + ${this.vbytesPipe.transform(item.value, 2, 'vB', 'MvB', false)} + + + + + ${this.vbytesPipe.transform(totalValueArray[index], 2, 'vB', 'MvB', false)} - + `); - } }); const classActive = (this.template === 'advanced') ? 'fees-wrapper-tooltip-chart-advanced' : ''; return `
- ${title} +
+ ${params[0].axisValue} + + ${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)} + +
@@ -332,5 +320,35 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }, }; } + + getTotalValues = (values: any) => { + let totalValueTemp = 0; + const totalValueArray = []; + const valuesInverted = this.inverted ? values : [...values].reverse(); + for (const item of valuesInverted) { + totalValueTemp += item.value; + totalValueArray.push(totalValueTemp); + } + return { + totalValue: totalValueTemp, + totalValueArray: totalValueArray.reverse(), + }; + } + + orderLevels() { + for (let i = 0; i < feeLevels.length; i++) { + if (feeLevels[i] === this.limitFilterFee) { + this.feeLimitIndex = i; + } + if (feeLevels[i] <= this.limitFee) { + if (i === 0) { + this.feeLevelsOrdered.push('0 - 1'); + } else { + this.feeLevelsOrdered.push(`${feeLevels[i - 1]} - ${feeLevels[i]}`); + } + } + } + this.chartColorsOrdered = chartColors.slice(0, this.feeLevelsOrdered.length); + } } diff --git a/frontend/src/app/components/statistics/statistics.component.html b/frontend/src/app/components/statistics/statistics.component.html index 9f80de314..df372db3f 100644 --- a/frontend/src/app/components/statistics/statistics.component.html +++ b/frontend/src/app/components/statistics/statistics.component.html @@ -36,6 +36,42 @@ 1Y + +
+ + +
+ @@ -45,8 +81,10 @@ dir="ltr" [template]="'advanced'" [limitFee]="500" + [limitFilterFee]="filterFeeIndex" [height]="500" [left]="65" + [right]="10" [data]="mempoolStats" > diff --git a/frontend/src/app/components/statistics/statistics.component.scss b/frontend/src/app/components/statistics/statistics.component.scss index 31eecb8c3..ca367bf17 100644 --- a/frontend/src/app/components/statistics/statistics.component.scss +++ b/frontend/src/app/components/statistics/statistics.component.scss @@ -61,3 +61,48 @@ .incoming-transactions-graph { height: 600px; } + + +.dropdown-fees { + padding: 10px 0px; + min-width: 130px; + padding: 2px ​20px 0px; + left: -38px !important; + position: absolute !important; + + ul { + list-style: none; + padding: 0px; + margin-bottom: 0px; + } + li { + width: 100%; + font-size: 14px; + padding: 0px 0px; + padding-left: 20px; + transition: 200ms all ease-in-out; + &:hover { + background-color: #10121e; + cursor: pointer; + } + } + .square { + transition: 200ms all ease-in-out; + height: 12px; + width: 12px; + margin-right: 10px; + border-radius: 1px; + display: inline-block; + position: relative; + top: 1px; + } + .inactive { + .square { + background-color: #ffffff66 !important; + } + .fee-text { + text-decoration: line-through; + color: #777; + } + } +} diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts index bd05dc6a1..a9041d1fe 100644 --- a/frontend/src/app/components/statistics/statistics.component.ts +++ b/frontend/src/app/components/statistics/statistics.component.ts @@ -11,6 +11,7 @@ import { ApiService } from '../../services/api.service'; import { StateService } from 'src/app/services/state.service'; import { SeoService } from 'src/app/services/seo.service'; import { StorageService } from 'src/app/services/storage.service'; +import { feeLevels, chartColors } from 'src/app/app.constants'; @Component({ selector: 'app-statistics', @@ -22,6 +23,10 @@ export class StatisticsComponent implements OnInit { loading = true; spinnerLoading = false; + feeLevels = feeLevels; + chartColors = chartColors; + filterFeeIndex = 1; + dropDownOpen = false; mempoolStats: OptimizedMempoolStats[] = []; @@ -30,7 +35,7 @@ export class StatisticsComponent implements OnInit { mempoolTransactionsWeightPerSecondData: any; radioGroupForm: FormGroup; - graphWindowPreference: String; + graphWindowPreference: string; inverted: boolean; constructor( @@ -46,6 +51,10 @@ export class StatisticsComponent implements OnInit { ngOnInit() { this.inverted = this.storageService.getValue('inverted-graph') === 'true'; + if (!this.inverted) { + this.feeLevels = [...feeLevels].reverse(); + this.chartColors = [...chartColors].reverse(); + } this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`); this.stateService.networkChanged$.subscribe((network) => this.network = network); this.graphWindowPreference = this.storageService.getValue('graphWindowPreference') ? this.storageService.getValue('graphWindowPreference').trim() : '2h'; @@ -131,4 +140,12 @@ export class StatisticsComponent implements OnInit { this.storageService.setValue('inverted-graph', !this.inverted); document.location.reload(); } + + filterFees(index: number) { + this.filterFeeIndex = index; + } + + filterClick() { + this.dropDownOpen = !this.dropDownOpen; + } } diff --git a/frontend/src/app/components/television/television.component.html b/frontend/src/app/components/television/television.component.html index e5134c9bd..3644c4d6a 100644 --- a/frontend/src/app/components/television/television.component.html +++ b/frontend/src/app/components/television/television.component.html @@ -11,6 +11,7 @@ [limitFee]="500" [height]="600" [left]="60" + [right]="10" [data]="mempoolStats" [showZoom]="false" >