diff --git a/frontend/cypress/integration/mainnet/mainnet.spec.ts b/frontend/cypress/integration/mainnet/mainnet.spec.ts index 7e56c7e97..5839f4f51 100644 --- a/frontend/cypress/integration/mainnet/mainnet.spec.ts +++ b/frontend/cypress/integration/mainnet/mainnet.spec.ts @@ -281,12 +281,12 @@ describe('Mainnet', () => { }); }); - it('loads the tv screen - mobile', () => { + it.only('loads the tv screen - mobile', () => { cy.viewport('iphone-6'); cy.visit('/tv'); cy.waitForSkeletonGone(); cy.get('.chart-holder'); - cy.get('.blockchain-wrapper').should('be.visible'); + cy.get('.blockchain-wrapper').should('not.visible'); }); it('loads the api screen', () => { diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts index dd4001821..e5951c261 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, Input, Inject, LOCALE_ID, ChangeDetectionStrategy } import { formatDate } from '@angular/common'; import { EChartsOption } from 'echarts'; import { OnChanges } from '@angular/core'; +import { StorageService } from 'src/app/services/storage.service'; @Component({ selector: 'app-incoming-transactions-graph', @@ -15,14 +16,18 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { @Input() right: number | string = '10'; @Input() top: number | string = '20'; @Input() left: number | string = '50'; + @Input() size: ('small' | 'big') = 'small'; mempoolStatsChartOption: EChartsOption = {}; + windowPreference: string; constructor( @Inject(LOCALE_ID) private locale: string, + private storageService: StorageService, ) { } ngOnChanges(): void { + this.windowPreference = this.storageService.getValue('graphWindowPreference'); this.mountChart(); } @@ -38,6 +43,24 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { top: this.top, left: this.left, }, + dataZoom: [{ + type: 'inside', + realtime: true, + }, { + show: (this.size === 'big') ? true : false, + type: 'slider', + brushSelect: false, + realtime: true, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + } + }], tooltip: { trigger: 'axis', position: (pos, params, el, elRect, size) => { @@ -45,25 +68,16 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 80; return obj; }, - extraCssText: `background: transparent; + extraCssText: `width: ${(['2h', '24h'].includes(this.windowPreference) || this.size === 'small') ? '105px' : '135px'}; + background: transparent; border: none; box-shadow: none;`, axisPointer: { - type: 'cross', - label: { - formatter: (axis: any) => { - if (axis.axisDimension === 'y') { - return `${Math.floor(axis.value)}`; - } - if (axis.axisDimension === 'x') { - return axis.value; - } - }, - } + type: 'line', }, formatter: (params: any) => { const colorSpan = (color: string) => `
`; - let itemFormatted = '
' + params[0].axisValue + '
'; + let itemFormatted = '
' + params[0].axisValue + '
'; params.map((item: any, index: number) => { if (index < 26) { itemFormatted += `
@@ -73,15 +87,18 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
`; } }); - if (this.theme !== '') { - return `
${itemFormatted}
`; - } - return `
${itemFormatted}
`; + return `
${itemFormatted}
`; } }, xAxis: { type: 'category', - data: this.data.labels.map((value: any) => formatDate(value, 'HH:mm', this.locale)), + data: this.data.labels.map((value: any) => { + if (['2h', '24h'].includes(this.windowPreference) || this.size === 'small') { + return formatDate(value, 'HH:mm', this.locale); + } else { + return formatDate(value, 'MM/dd - HH:mm', this.locale); + } + }), }, yAxis: { type: 'value', diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.html b/frontend/src/app/components/mempool-graph/mempool-graph.component.html index 0ea3867a8..a4cac25b7 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.html +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.html @@ -1 +1 @@ -
+
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 2b384d7e8..f6e7761fe 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -7,13 +7,6 @@ import { StorageService } from 'src/app/services/storage.service'; import { EChartsOption } from 'echarts'; import { feeLevels, chartColors } from 'src/app/app.constants'; -interface AxisObject { - axisDimension: string; - axisIndex: number; - seriesData: any; - value: string; -} - @Component({ selector: 'app-mempool-graph', templateUrl: './mempool-graph.component.html', @@ -26,18 +19,18 @@ export class MempoolGraphComponent implements OnInit, OnChanges { @Input() top: number | string = 20; @Input() right: number | string = 10; @Input() left: number | string = 75; - @Input() dateSpan = '2h'; - @Input() showLegend = true; @Input() small = false; + @Input() size: ('small' | 'big') = 'small'; mempoolVsizeFeesData: any; mempoolVsizeFeesOptions: EChartsOption; - - inverted: boolean; + windowPreference: string; + hoverIndexSerie: -1; constructor( private vbytesPipe: VbytesPipe, private stateService: StateService, + private storageService: StorageService, @Inject(LOCALE_ID) private locale: string, ) { } @@ -46,11 +39,17 @@ export class MempoolGraphComponent implements OnInit, OnChanges { } ngOnChanges() { - // this.inverted = this.storageService.getValue('inverted-graph') === 'true'; + this.windowPreference = this.storageService.getValue('graphWindowPreference'); this.mempoolVsizeFeesData = this.handleNewMempoolData(this.data.concat([])); this.mountFeeChart(); } + onChartReady(myChart: any) { + myChart.on('mouseover', 'series', (serie: any) => { + this.hoverIndexSerie = serie.seriesIndex; + }); + } + handleNewMempoolData(mempoolStats: OptimizedMempoolStats[]) { mempoolStats.reverse(); const labels = mempoolStats.map(stats => stats.added); @@ -81,9 +80,9 @@ export class MempoolGraphComponent implements OnInit, OnChanges { feesArray.push(0); } }); - // if (this.inverted && finalArray.length) { - // feesArray = feesArray.map((value, i) => value + finalArray[finalArray.length - 1][i]); - // } + if (finalArray.length) { + feesArray = feesArray.map((value, i) => value + finalArray[finalArray.length - 1][i]); + } finalArray.push(feesArray); } finalArray.reverse(); @@ -93,45 +92,45 @@ export class MempoolGraphComponent implements OnInit, OnChanges { mountFeeChart(){ const { labels, series } = this.mempoolVsizeFeesData; - const legendNames: string[] = feeLevels.map((sat, i, arr) => { - if (sat > this.limitFee) { return `${this.limitFee}+`; } - if (i === 0) { return '0 - 1'; } - return arr[i - 1] + ' - ' + sat; + const feeLevelsOrdered = feeLevels.map((sat, i, arr) => { + if (i <= 26) { + if (i === 0) { return '0 - 1'; } + if (i === 26) { return '350+'; } + return arr[i - 1] + ' - ' + sat; + } }); const yAxisSeries = series.map((value: Array, index: number) => { - return { - name: labels[index].name, - type: 'line', - stack: 'total', - smooth: false, - lineStyle: { - width: 0, - opacity: 0, - }, - showSymbol: false, - areaStyle: { - opacity: 1, - color: chartColors[index], - }, - emphasis: { - focus: 'series' - }, - markLine: { - symbol: 'none', - itemStyle: { - borderWidth: 0, - borderColor: 'none', - color: '#fff', + if (index <= 26){ + return { + name: feeLevelsOrdered[index], + type: 'line', + stack: 'total', + smooth: false, + markPoint: { + symbol: 'rect', }, lineStyle: { - color: '#fff', - opacity: 0.75, - width: 2, + width: 0, + opacity: 0, }, - }, - data: this.vbytesPipe.transform(value, 2, 'vB', 'MvB', true) - }; + symbolSize: (this.size === 'big') ? 15 : 10, + showSymbol: false, + areaStyle: { + opacity: 1, + color: chartColors[index], + }, + emphasis: { + focus: 'series', + }, + itemStyle: { + borderWidth: 30, + color: chartColors[index], + borderColor: chartColors[index], + }, + data: this.vbytesPipe.transform(value, 2, 'vB', 'MvB', true) + }; + } }); this.mempoolVsizeFeesOptions = { @@ -143,39 +142,57 @@ export class MempoolGraphComponent implements OnInit, OnChanges { positions[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 80; return positions; }, - extraCssText: `width: 150px; + extraCssText: `width: ${(this.size === 'big') ? '200px' : '170px'}; background: transparent; border: none; box-shadow: none;`, axisPointer: { - type: 'cross', - label: { - formatter: (axis: AxisObject) => { - if (axis.axisDimension === 'y') { - return `${this.vbytesPipe.transform(axis.value, 2, 'vB', 'MvB', true)}`; - } - if (axis.axisDimension === 'x') { - return axis.value; - } - }, - } + type: 'line', }, formatter: (params: any) => { const colorSpan = (index: number) => `
`; - const legendName = (index: number) => legendNames[index]; - let itemFormatted = '
' + params[0].axisValue + '
'; + const legendName = (index: number) => feeLevelsOrdered[index]; + let itemFormatted = `
${params[0].axisValue}
`; + let total = 0; params.map((item: any, index: number) => { - if (feeLevels[index - 1] < this.limitFee) { - itemFormatted += `
- ${colorSpan(index - 1)} ${legendName(index)} + total += item.value; + if (index <= 26) { + let activeItemClass = ''; + if (this.hoverIndexSerie === index){ + activeItemClass = 'active'; + } + itemFormatted += `
+ ${colorSpan(index)} ${legendName(index)}
-
${this.vbytesPipe.transform(item.value, 2, 'vB', 'MvB', true)}
+
${this.vbytesPipe.transform(item.value, 2, 'vB', 'MvB', false)}
`; } }); - return `
${itemFormatted}
`; + const totalDiv = `
Total + ${this.vbytesPipe.transform(total, 2, 'vB', 'MvB', true)} +
`; + const bigClass = (this.size === 'big') ? 'fees-wrapper-tooltip-chart-big' : ''; + return `
${itemFormatted} ${totalDiv}
`; } }, + dataZoom: [{ + type: 'inside', + realtime: true, + }, { + show: (this.size === 'big') ? true : false, + type: 'slider', + brushSelect: false, + realtime: true, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + } + }], grid: { height: this.height, right: this.right, @@ -186,11 +203,19 @@ export class MempoolGraphComponent implements OnInit, OnChanges { { type: 'category', boundaryGap: false, - data: labels.map((value: any) => formatDate(value, 'HH:mm', this.locale)), + axisLine: { onZero: false }, + data: labels.map((value: any) => { + if (['2h', '24h'].includes(this.windowPreference) || this.size === 'small') { + return formatDate(value, 'HH:mm', this.locale); + } else { + return formatDate(value, 'MM/dd - HH:mm', this.locale); + } + }), } ], yAxis: { type: 'value', + axisLine: { onZero: false }, axisLabel: { formatter: (value: number) => (`${this.vbytesPipe.transform(value, 2, 'vB', 'MvB', true)}`), }, diff --git a/frontend/src/app/components/statistics/statistics.component.html b/frontend/src/app/components/statistics/statistics.component.html index b932c746c..8e8677267 100644 --- a/frontend/src/app/components/statistics/statistics.component.html +++ b/frontend/src/app/components/statistics/statistics.component.html @@ -36,25 +36,36 @@ 1Y
-
- +
-
+
Transaction vBytes per second (vB/s)
- +
diff --git a/frontend/src/app/components/television/television.component.html b/frontend/src/app/components/television/television.component.html index d12564c30..5b8d52bb3 100644 --- a/frontend/src/app/components/television/television.component.html +++ b/frontend/src/app/components/television/television.component.html @@ -5,8 +5,15 @@
-
- +
+
diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 09255a76f..39c7292f0 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -255,7 +255,7 @@ html:lang(ru) .card-title { font-size: 0.9rem; } -/* MEMPOOL CHARTS */ +/* MEMPOOL CHARTS - start */ .mempool-wrapper-tooltip-chart { height: 250px; @@ -267,54 +267,116 @@ html:lang(ru) .card-title { } .tx-wrapper-tooltip-chart, .fees-wrapper-tooltip-chart { - display: flex; - justify-content: space-between; - flex-direction: column; background: rgba(#11131f, 0.85); - color: #fff; - padding: 10px 15px; border-radius: 4px; box-shadow: 1px 1px 10px rgba(0,0,0,0.2); + color: #b1b1b1; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 10px 15px; + text-align: left; + .title { + font-size: 12px; + font-weight: 700; + margin-bottom: 2px; + color: #fff; + } + .active { + color: yellow !important; + font-weight: 900; + .value { + .symbol { + color: yellow !important; + } + } + } .item { - text-align: left; display: flex; .indicator { - display: block; margin-right: 5px; - border-radius: 10px; + border-radius: 0px; margin-top: 5px; width: 9px; height: 9px; } .value { text-align: right; - span { - color: #212121 !important; + .symbol { + color: #7e7e7e; + font-size: 9px !important; } } } -} - -.grow { - flex-grow: 1; + .total-label { + width: 100%; + margin-top: 0px; + font-size: 10px; + text-align: left; + color: #fff; + span { + font-weight: 700; + float: right !important; + } + } } .fees-wrapper-tooltip-chart { .item { font-size: 9px; line-height: 1; + margin: 0px; } .indicator { margin-right: 5px !important; - border-radius: 10px !important; + border-radius: 1px !important; margin-top: 0px !important; } } +.fees-wrapper-tooltip-chart-big, .tx-wrapper-tooltip-chart-big { + background: rgba(#1d1f31, 0.85); + .title { + font-size: 15px; + margin-bottom: 5px; + } + .item { + font-size: 12px; + line-height: 1; + margin: 2px 0px; + .value { + .symbol { + font-size: 12px !important; + } + } + } + .total-label { + width: 100%; + margin-top: 5px; + font-size: 14px; + span { + font-weight: 700; + float: right !important; + } + } +} + +.tx-wrapper-tooltip-chart-big { + .indicator { + margin: 0px !important;; + } +} + .fee-distribution-chart { height: 250px; } +/* MEMPOOL CHARTS - end */ + +.grow { + flex-grow: 1; +} + hr { border-top: 1px solid rgba(255, 255, 255, 0.1); }