Merge pull request #1004 from jorisvial/bug/improve-x-axis-intervals
Improve x-axis labels and graph data ticks
This commit is contained in:
commit
e67f552fbd
@ -267,8 +267,57 @@ class Statistics {
|
||||
}
|
||||
}
|
||||
|
||||
private getQueryForDays(div: number) {
|
||||
return `SELECT id, added, unconfirmed_transactions,
|
||||
private getQueryForDaysAvg(div: number, interval: string) {
|
||||
return `SELECT id, UNIX_TIMESTAMP(added) as added,
|
||||
CAST(avg(unconfirmed_transactions) as FLOAT) as unconfirmed_transactions,
|
||||
CAST(avg(tx_per_second) as FLOAT) as tx_per_second,
|
||||
CAST(avg(vbytes_per_second) as FLOAT) as vbytes_per_second,
|
||||
CAST(avg(vsize_1) as FLOAT) as vsize_1,
|
||||
CAST(avg(vsize_2) as FLOAT) as vsize_2,
|
||||
CAST(avg(vsize_3) as FLOAT) as vsize_3,
|
||||
CAST(avg(vsize_4) as FLOAT) as vsize_4,
|
||||
CAST(avg(vsize_5) as FLOAT) as vsize_5,
|
||||
CAST(avg(vsize_6) as FLOAT) as vsize_6,
|
||||
CAST(avg(vsize_8) as FLOAT) as vsize_8,
|
||||
CAST(avg(vsize_10) as FLOAT) as vsize_10,
|
||||
CAST(avg(vsize_12) as FLOAT) as vsize_12,
|
||||
CAST(avg(vsize_15) as FLOAT) as vsize_15,
|
||||
CAST(avg(vsize_20) as FLOAT) as vsize_20,
|
||||
CAST(avg(vsize_30) as FLOAT) as vsize_30,
|
||||
CAST(avg(vsize_40) as FLOAT) as vsize_40,
|
||||
CAST(avg(vsize_50) as FLOAT) as vsize_50,
|
||||
CAST(avg(vsize_60) as FLOAT) as vsize_60,
|
||||
CAST(avg(vsize_70) as FLOAT) as vsize_70,
|
||||
CAST(avg(vsize_80) as FLOAT) as vsize_80,
|
||||
CAST(avg(vsize_90) as FLOAT) as vsize_90,
|
||||
CAST(avg(vsize_100) as FLOAT) as vsize_100,
|
||||
CAST(avg(vsize_125) as FLOAT) as vsize_125,
|
||||
CAST(avg(vsize_150) as FLOAT) as vsize_150,
|
||||
CAST(avg(vsize_175) as FLOAT) as vsize_175,
|
||||
CAST(avg(vsize_200) as FLOAT) as vsize_200,
|
||||
CAST(avg(vsize_250) as FLOAT) as vsize_250,
|
||||
CAST(avg(vsize_300) as FLOAT) as vsize_300,
|
||||
CAST(avg(vsize_350) as FLOAT) as vsize_350,
|
||||
CAST(avg(vsize_400) as FLOAT) as vsize_400,
|
||||
CAST(avg(vsize_500) as FLOAT) as vsize_500,
|
||||
CAST(avg(vsize_600) as FLOAT) as vsize_600,
|
||||
CAST(avg(vsize_700) as FLOAT) as vsize_700,
|
||||
CAST(avg(vsize_800) as FLOAT) as vsize_800,
|
||||
CAST(avg(vsize_900) as FLOAT) as vsize_900,
|
||||
CAST(avg(vsize_1000) as FLOAT) as vsize_1000,
|
||||
CAST(avg(vsize_1200) as FLOAT) as vsize_1200,
|
||||
CAST(avg(vsize_1400) as FLOAT) as vsize_1400,
|
||||
CAST(avg(vsize_1600) as FLOAT) as vsize_1600,
|
||||
CAST(avg(vsize_1800) as FLOAT) as vsize_1800,
|
||||
CAST(avg(vsize_2000) as FLOAT) as vsize_2000 \
|
||||
FROM statistics \
|
||||
WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \
|
||||
GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \
|
||||
ORDER BY id DESC;`;
|
||||
}
|
||||
|
||||
private getQueryForDays(div: number, interval: string) {
|
||||
return `SELECT id, UNIX_TIMESTAMP(added) as added, unconfirmed_transactions,
|
||||
tx_per_second,
|
||||
vbytes_per_second,
|
||||
vsize_1,
|
||||
@ -308,13 +357,17 @@ class Statistics {
|
||||
vsize_1400,
|
||||
vsize_1600,
|
||||
vsize_1800,
|
||||
vsize_2000 FROM statistics GROUP BY UNIX_TIMESTAMP(added) DIV ${div} ORDER BY id DESC LIMIT 480`;
|
||||
vsize_2000 \
|
||||
FROM statistics \
|
||||
WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \
|
||||
GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \
|
||||
ORDER BY id DESC;`;
|
||||
}
|
||||
|
||||
public async $get(id: number): Promise<OptimizedStatistic | undefined> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = `SELECT * FROM statistics WHERE id = ?`;
|
||||
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE id = ?`;
|
||||
const [rows] = await connection.query<any>(query, [id]);
|
||||
connection.release();
|
||||
if (rows[0]) {
|
||||
@ -328,7 +381,7 @@ class Statistics {
|
||||
public async $list2H(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = `SELECT * FROM statistics ORDER BY id DESC LIMIT 120`;
|
||||
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY id DESC LIMIT 120`;
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -341,7 +394,7 @@ class Statistics {
|
||||
public async $list24H(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(180);
|
||||
const query = this.getQueryForDaysAvg(120, '1 DAY'); // 2m interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -354,7 +407,7 @@ class Statistics {
|
||||
public async $list1W(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(1260);
|
||||
const query = this.getQueryForDaysAvg(600, '1 WEEK'); // 10m interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -367,7 +420,7 @@ class Statistics {
|
||||
public async $list1M(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(5040);
|
||||
const query = this.getQueryForDaysAvg(3600, '1 MONTH'); // 1h interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -380,7 +433,7 @@ class Statistics {
|
||||
public async $list3M(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(15120);
|
||||
const query = this.getQueryForDaysAvg(14400, '3 MONTH'); // 4h interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -393,7 +446,7 @@ class Statistics {
|
||||
public async $list6M(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(30240);
|
||||
const query = this.getQueryForDaysAvg(21600, '6 MONTH'); // 6h interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -406,7 +459,7 @@ class Statistics {
|
||||
public async $list1Y(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(60480);
|
||||
const query = this.getQueryForDays(43200, '1 YEAR'); // 12h interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -419,7 +472,7 @@ class Statistics {
|
||||
public async $list2Y(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(120960);
|
||||
const query = this.getQueryForDays(86400, "2 YEAR"); // 1d interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
@ -432,7 +485,7 @@ class Statistics {
|
||||
public async $list3Y(): Promise<OptimizedStatistic[]> {
|
||||
try {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const query = this.getQueryForDays(181440);
|
||||
const query = this.getQueryForDays(86400, "3 YEAR"); // 1d interval
|
||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||
connection.release();
|
||||
return this.mapStatisticToOptimizedStatistic(rows);
|
||||
|
@ -32,7 +32,6 @@ import { BlockchainComponent } from './components/blockchain/blockchain.componen
|
||||
import { FooterComponent } from './components/footer/footer.component';
|
||||
import { AudioService } from './services/audio.service';
|
||||
import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component';
|
||||
import { FeeDistributionGraphComponent } from './components/fee-distribution-graph/fee-distribution-graph.component';
|
||||
import { IncomingTransactionsGraphComponent } from './components/incoming-transactions-graph/incoming-transactions-graph.component';
|
||||
import { TimeSpanComponent } from './components/time-span/time-span.component';
|
||||
import { SeoService } from './services/seo.service';
|
||||
@ -84,7 +83,6 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra
|
||||
MempoolBlocksComponent,
|
||||
FooterComponent,
|
||||
MempoolBlockComponent,
|
||||
FeeDistributionGraphComponent,
|
||||
IncomingTransactionsGraphComponent,
|
||||
MempoolGraphComponent,
|
||||
LbtcPegsGraphComponent,
|
||||
|
@ -1,9 +0,0 @@
|
||||
<div class="fee-distribution-chart" *ngIf="mempoolVsizeFeesOptions; else loadingFees">
|
||||
<div echarts [initOpts]="mempoolVsizeFeesInitOptions" [options]="mempoolVsizeFeesOptions"></div>
|
||||
</div>
|
||||
|
||||
<ng-template #loadingFees>
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-light"></div>
|
||||
</div>
|
||||
</ng-template>
|
@ -1,83 +0,0 @@
|
||||
import { OnChanges } from '@angular/core';
|
||||
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-fee-distribution-graph',
|
||||
templateUrl: './fee-distribution-graph.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FeeDistributionGraphComponent implements OnInit, OnChanges {
|
||||
@Input() data: any;
|
||||
@Input() height: number | string = 210;
|
||||
@Input() top: number | string = 20;
|
||||
@Input() right: number | string = 22;
|
||||
@Input() left: number | string = 30;
|
||||
|
||||
mempoolVsizeFeesOptions: any;
|
||||
mempoolVsizeFeesInitOptions = {
|
||||
renderer: 'svg'
|
||||
};
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
this.mountChart();
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.mountChart();
|
||||
}
|
||||
|
||||
mountChart() {
|
||||
this.mempoolVsizeFeesOptions = {
|
||||
grid: {
|
||||
height: '210',
|
||||
right: '20',
|
||||
top: '22',
|
||||
left: '30',
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dotted',
|
||||
color: '#ffffff66',
|
||||
opacity: 0.25,
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
data: this.data,
|
||||
type: 'line',
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
color: '#ffffff',
|
||||
textShadowBlur: 0,
|
||||
formatter: (label: any) => {
|
||||
return Math.floor(label.data);
|
||||
},
|
||||
},
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
color: '#D81B60',
|
||||
width: 4,
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#b71c1c',
|
||||
borderWidth: 10,
|
||||
borderMiterLimit: 10,
|
||||
opacity: 1,
|
||||
},
|
||||
areaStyle: {
|
||||
color: '#D81B60',
|
||||
opacity: 1,
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { Component, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { EChartsOption } from 'echarts';
|
||||
import { OnChanges } from '@angular/core';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-incoming-transactions-graph',
|
||||
@ -25,6 +25,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
||||
@Input() top: number | string = '20';
|
||||
@Input() left: number | string = '0';
|
||||
@Input() template: ('widget' | 'advanced') = 'widget';
|
||||
@Input() windowPreferenceOverride: string;
|
||||
|
||||
isLoading = true;
|
||||
mempoolStatsChartOption: EChartsOption = {};
|
||||
@ -46,7 +47,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
||||
if (!this.data) {
|
||||
return;
|
||||
}
|
||||
this.windowPreference = this.storageService.getValue('graphWindowPreference');
|
||||
this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference');
|
||||
this.mountChart();
|
||||
}
|
||||
|
||||
@ -73,10 +74,12 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
||||
maxSpan: 100,
|
||||
minSpan: 10,
|
||||
}, {
|
||||
showDetail: false,
|
||||
show: (this.template === 'advanced') ? true : false,
|
||||
type: 'slider',
|
||||
brushSelect: false,
|
||||
realtime: true,
|
||||
bottom: 0,
|
||||
selectedDataBackground: {
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
@ -85,7 +88,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
||||
areaStyle: {
|
||||
opacity: 0,
|
||||
}
|
||||
}
|
||||
},
|
||||
}],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
@ -102,29 +105,39 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
||||
type: 'line',
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
const axisValueLabel: string = formatterXAxis(this.locale, this.windowPreference, params[0].axisValue);
|
||||
const colorSpan = (color: string) => `<span class="indicator" style="background-color: ` + color + `"></span>`;
|
||||
let itemFormatted = '<div class="title">' + params[0].axisValue + '</div>';
|
||||
let itemFormatted = '<div class="title">' + axisValueLabel + '</div>';
|
||||
params.map((item: any, index: number) => {
|
||||
if (index < 26) {
|
||||
itemFormatted += `<div class="item">
|
||||
<div class="indicator-container">${colorSpan(item.color)}</div>
|
||||
<div class="grow"></div>
|
||||
<div class="value">${item.value} <span class="symbol">vB/s</span></div>
|
||||
<div class="value">${item.value[1]} <span class="symbol">vB/s</span></div>
|
||||
</div>`;
|
||||
}
|
||||
});
|
||||
return `<div class="tx-wrapper-tooltip-chart ${(this.template === 'advanced') ? 'tx-wrapper-tooltip-chart-advanced' : ''}">${itemFormatted}</div>`;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLabel: {
|
||||
align: 'center',
|
||||
fontSize: 11,
|
||||
lineHeight: 12
|
||||
},
|
||||
data: this.data.labels.map((value: any) => `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}`),
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
name: formatterXAxisLabel(this.locale, this.windowPreference),
|
||||
nameLocation: 'middle',
|
||||
nameTextStyle: {
|
||||
padding: [20, 0, 0, 0],
|
||||
},
|
||||
type: 'time',
|
||||
axisLabel: {
|
||||
margin: 20,
|
||||
align: 'center',
|
||||
fontSize: 11,
|
||||
lineHeight: 12,
|
||||
hideOverlap: true,
|
||||
padding: [0, 5],
|
||||
},
|
||||
}
|
||||
],
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
|
@ -40,9 +40,6 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md chart-container">
|
||||
<app-fee-distribution-graph [data]="mempoolBlock.feeRange" ></app-fee-distribution-graph>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { Component, OnInit, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnChanges } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { VbytesPipe } from 'src/app/shared/pipes/bytes-pipe/vbytes.pipe';
|
||||
import { formatNumber } from "@angular/common";
|
||||
|
||||
import { OptimizedMempoolStats } from 'src/app/interfaces/node-api.interface';
|
||||
import { StateService } from 'src/app/services/state.service';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { EChartsOption } from 'echarts';
|
||||
import { feeLevels, chartColors } from 'src/app/app.constants';
|
||||
import { formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-mempool-graph',
|
||||
@ -32,6 +31,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
@Input() left: number | string = 75;
|
||||
@Input() template: ('widget' | 'advanced') = 'widget';
|
||||
@Input() showZoom = true;
|
||||
@Input() windowPreferenceOverride: string;
|
||||
|
||||
isLoading = true;
|
||||
mempoolVsizeFeesData: any;
|
||||
@ -62,7 +62,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
if (!this.data) {
|
||||
return;
|
||||
}
|
||||
this.windowPreference = this.storageService.getValue('graphWindowPreference');
|
||||
this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference');
|
||||
this.mempoolVsizeFeesData = this.handleNewMempoolData(this.data.concat([]));
|
||||
this.mountFeeChart();
|
||||
}
|
||||
@ -97,13 +97,13 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
generateArray(mempoolStats: OptimizedMempoolStats[]) {
|
||||
const finalArray: number[][] = [];
|
||||
let feesArray: number[] = [];
|
||||
const finalArray: number[][][] = [];
|
||||
let feesArray: number[][] = [];
|
||||
let limitFeesTemplate = this.template === 'advanced' ? 26 : 20;
|
||||
for (let index = limitFeesTemplate; index > -1; index--) {
|
||||
feesArray = [];
|
||||
mempoolStats.forEach((stats) => {
|
||||
feesArray.push(stats.vsizes[index] ? stats.vsizes[index] : 0);
|
||||
feesArray.push([stats.added * 1000, stats.vsizes[index] ? stats.vsizes[index] : 0]);
|
||||
});
|
||||
finalArray.push(feesArray);
|
||||
}
|
||||
@ -113,7 +113,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
|
||||
mountFeeChart() {
|
||||
this.orderLevels();
|
||||
const { labels, series } = this.mempoolVsizeFeesData;
|
||||
const { series } = this.mempoolVsizeFeesData;
|
||||
|
||||
const seriesGraph = [];
|
||||
const newColors = [];
|
||||
@ -186,14 +186,15 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
type: 'line',
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
const axisValueLabel: string = formatterXAxis(this.locale, this.windowPreference, params[0].axisValue);
|
||||
const { totalValue, totalValueArray } = this.getTotalValues(params);
|
||||
const itemFormatted = [];
|
||||
let totalParcial = 0;
|
||||
let progressPercentageText = '';
|
||||
const items = this.inverted ? [...params].reverse() : params;
|
||||
items.map((item: any, index: number) => {
|
||||
totalParcial += item.value;
|
||||
const progressPercentage = (item.value / totalValue) * 100;
|
||||
totalParcial += item.value[1];
|
||||
const progressPercentage = (item.value[1] / totalValue) * 100;
|
||||
const progressPercentageSum = (totalValueArray[index] / totalValue) * 100;
|
||||
let activeItemClass = '';
|
||||
let hoverActive = 0;
|
||||
@ -233,7 +234,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
</td>
|
||||
<td class="total-progress-sum">
|
||||
<span>
|
||||
${this.vbytesPipe.transform(item.value, 2, 'vB', 'MvB', false)}
|
||||
${this.vbytesPipe.transform(item.value[1], 2, 'vB', 'MvB', false)}
|
||||
</span>
|
||||
</td>
|
||||
<td class="total-progress-sum">
|
||||
@ -257,7 +258,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
const titleSum = $localize`Sum`;
|
||||
return `<div class="fees-wrapper-tooltip-chart ${classActive}">
|
||||
<div class="title">
|
||||
${params[0].axisValue}
|
||||
${axisValueLabel}
|
||||
<span class="total-value">
|
||||
${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)}
|
||||
</span>
|
||||
@ -288,6 +289,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
maxSpan: 100,
|
||||
minSpan: 10,
|
||||
}, {
|
||||
showDetail: false,
|
||||
show: (this.template === 'advanced' && this.showZoom) ? true : false,
|
||||
type: 'slider',
|
||||
brushSelect: false,
|
||||
@ -312,15 +314,22 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
name: formatterXAxisLabel(this.locale, this.windowPreference),
|
||||
nameLocation: 'middle',
|
||||
nameTextStyle: {
|
||||
padding: [20, 0, 0, 0],
|
||||
},
|
||||
type: 'time',
|
||||
boundaryGap: false,
|
||||
axisLine: { onZero: true },
|
||||
axisLabel: {
|
||||
margin: 20,
|
||||
align: 'center',
|
||||
fontSize: 11,
|
||||
lineHeight: 12,
|
||||
hideOverlap: true,
|
||||
padding: [0, 5],
|
||||
},
|
||||
data: labels.map((value: any) => `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}`),
|
||||
}
|
||||
],
|
||||
yAxis: {
|
||||
@ -346,7 +355,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
const totalValueArray = [];
|
||||
const valuesInverted = this.inverted ? values : [...values].reverse();
|
||||
for (const item of valuesInverted) {
|
||||
totalValueTemp += item.value;
|
||||
totalValueTemp += item.value[1];
|
||||
totalValueArray.push(totalValueTemp);
|
||||
}
|
||||
return {
|
||||
|
@ -134,7 +134,7 @@ export class StatisticsComponent implements OnInit {
|
||||
|
||||
this.mempoolTransactionsWeightPerSecondData = {
|
||||
labels: labels,
|
||||
series: [mempoolStats.map((stats) => stats.vbytes_per_second)],
|
||||
series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])],
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
||||
[limitFee]="150"
|
||||
[limitFilterFee]="1"
|
||||
[data]="mempoolStats.value?.mempool"
|
||||
[windowPreferenceOverride]="'2h'"
|
||||
></app-mempool-graph>
|
||||
</div>
|
||||
</ng-container>
|
||||
@ -73,6 +74,7 @@
|
||||
<app-incoming-transactions-graph
|
||||
[left]="50"
|
||||
[data]="mempoolStats.value?.weightPerSecond"
|
||||
[windowPreferenceOverride]="'2h'"
|
||||
></app-incoming-transactions-graph>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -254,7 +254,6 @@ export class DashboardComponent implements OnInit {
|
||||
);
|
||||
}),
|
||||
map((mempoolStats) => {
|
||||
const data = this.handleNewMempoolData(mempoolStats.concat([]));
|
||||
return {
|
||||
mempool: mempoolStats,
|
||||
weightPerSecond: this.handleNewMempoolData(mempoolStats.concat([])),
|
||||
@ -286,7 +285,7 @@ export class DashboardComponent implements OnInit {
|
||||
|
||||
return {
|
||||
labels: labels,
|
||||
series: [mempoolStats.map((stats) => stats.vbytes_per_second)],
|
||||
series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])],
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
export interface OptimizedMempoolStats {
|
||||
id: number;
|
||||
added: string;
|
||||
added: number;
|
||||
unconfirmed_transactions: number;
|
||||
tx_per_second: number;
|
||||
vbytes_per_second: number;
|
||||
|
@ -1,9 +1,25 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StorageService {
|
||||
constructor(private router: Router, private route: ActivatedRoute) {
|
||||
let graphWindowPreference: string = this.getValue('graphWindowPreference');
|
||||
if (graphWindowPreference === null) { // First visit to mempool.space
|
||||
if (this.router.url.includes("graphs")) {
|
||||
this.setValue('graphWindowPreference', this.route.snapshot.fragment ? this.route.snapshot.fragment : "2h");
|
||||
} else {
|
||||
this.setValue('graphWindowPreference', "2h");
|
||||
}
|
||||
} else if (this.router.url.includes("graphs")) { // Visit a different graphs#fragment from last visit
|
||||
if (this.route.snapshot.fragment !== null && graphWindowPreference !== this.route.snapshot.fragment) {
|
||||
this.setValue('graphWindowPreference', this.route.snapshot.fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getValue(key: string): string {
|
||||
try {
|
||||
return localStorage.getItem(key);
|
||||
|
50
frontend/src/app/shared/graphs.utils.ts
Normal file
50
frontend/src/app/shared/graphs.utils.ts
Normal file
@ -0,0 +1,50 @@
|
||||
export const formatterXAxis = (
|
||||
locale: string,
|
||||
windowPreference: string,
|
||||
value: string
|
||||
) => {
|
||||
|
||||
if(value.length === 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
const date = new Date(value);
|
||||
switch (windowPreference) {
|
||||
case '2h':
|
||||
return date.toLocaleTimeString(locale, { hour: 'numeric', minute: 'numeric' });
|
||||
case '24h':
|
||||
return date.toLocaleTimeString(locale, { weekday: 'short', hour: 'numeric', minute: 'numeric' });
|
||||
case '1w':
|
||||
return date.toLocaleTimeString(locale, { month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' });
|
||||
case '1m':
|
||||
case '3m':
|
||||
case '6m':
|
||||
case '1y':
|
||||
return date.toLocaleTimeString(locale, { month: 'short', day: 'numeric', hour: 'numeric' });
|
||||
case '2y':
|
||||
case '3y':
|
||||
return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' });
|
||||
}
|
||||
};
|
||||
|
||||
export const formatterXAxisLabel = (
|
||||
locale: string,
|
||||
windowPreference: string,
|
||||
) => {
|
||||
const date = new Date();
|
||||
switch (windowPreference) {
|
||||
case '2h':
|
||||
case '24h':
|
||||
return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' });
|
||||
case '1w':
|
||||
return date.toLocaleDateString(locale, { year: 'numeric', month: 'long' });
|
||||
case '1m':
|
||||
case '3m':
|
||||
case '6m':
|
||||
return date.toLocaleDateString(locale, { year: 'numeric' });
|
||||
case '1y':
|
||||
case '2y':
|
||||
case '3y':
|
||||
return null;
|
||||
}
|
||||
};
|
@ -555,7 +555,7 @@ html:lang(ru) .card-title {
|
||||
}
|
||||
|
||||
.tx-wrapper-tooltip-chart-advanced {
|
||||
width: 115px;
|
||||
width: 140px;
|
||||
.indicator-container {
|
||||
.indicator {
|
||||
margin-right: 5px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user