From 00352d7e36a0c0fa7e050cddcfff7b97c71009b3 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 9 Dec 2021 22:04:23 +0900 Subject: [PATCH 01/16] Use "natural" intervals for x-axis in charts --- backend/src/api/statistics.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index 6cdfd72e7..8aad48e2b 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -267,7 +267,7 @@ class Statistics { } } - private getQueryForDays(div: number) { + private getQueryForDays(div: number, limit: number) { return `SELECT id, added, unconfirmed_transactions, tx_per_second, vbytes_per_second, @@ -308,7 +308,7 @@ 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 GROUP BY UNIX_TIMESTAMP(added) DIV ${div} ORDER BY id DESC LIMIT ${limit}`; } public async $get(id: number): Promise { @@ -341,7 +341,7 @@ class Statistics { public async $list24H(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(180); + const query = this.getQueryForDays(300, 288); // 5m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -354,7 +354,7 @@ class Statistics { public async $list1W(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(1260); + const query = this.getQueryForDays(1800, 336); // 30m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -367,7 +367,7 @@ class Statistics { public async $list1M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(5040); + const query = this.getQueryForDays(7200, 372); // 4h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -380,7 +380,7 @@ class Statistics { public async $list3M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(15120); + const query = this.getQueryForDays(21600, 372); // 6h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -393,7 +393,7 @@ class Statistics { public async $list6M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(30240); + const query = this.getQueryForDays(43200, 372); // 12h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -406,7 +406,7 @@ class Statistics { public async $list1Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(60480); + const query = this.getQueryForDays(86400, 365); // 1d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -419,7 +419,7 @@ class Statistics { public async $list2Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120960); + const query = this.getQueryForDays(172800, 365); // 2d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -432,7 +432,7 @@ class Statistics { public async $list3Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(181440); + const query = this.getQueryForDays(259200, 365); // 3d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); From 2b3463519a561fa7461a9ef17efd07741409bebb Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 9 Dec 2021 22:29:40 +0900 Subject: [PATCH 02/16] Format date properly according to the chosen time scale --- .../incoming-transactions-graph.component.ts | 25 ++++++++++++++++++- .../mempool-graph/mempool-graph.component.ts | 25 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) 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 622b8a296..b1c2399e1 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 @@ -123,7 +123,30 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { fontSize: 11, lineHeight: 12 }, - data: this.data.labels.map((value: any) => `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}`), + data: this.data.labels.map((value: any) => { + switch (this.windowPreference) { + case "2h": + return `${formatDate(value, 'h:mm a', this.locale)}` + case "24h": + return `${formatDate(value, 'h a', this.locale)}` + case "1w": + return `${formatDate(value, 'EEE, MMM d', this.locale)}` + case "1m": + return `${formatDate(value, 'EEE, MMM d', this.locale)}` + case "3m": + return `${formatDate(value, 'MMM d', this.locale)}` + case "6m": + return `${formatDate(value, 'MMM d', this.locale)}` + case "1y": + return `${formatDate(value, 'MMM y', this.locale)}` + case "2y": + return `${formatDate(value, 'MMM y', this.locale)}` + case "3y": + return `${formatDate(value, 'MMM y', this.locale)}` + default: + return `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}` + } + }), }, yAxis: { type: 'value', 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 3fd8912fd..ce4550759 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -320,7 +320,30 @@ export class MempoolGraphComponent implements OnInit, OnChanges { fontSize: 11, lineHeight: 12, }, - data: labels.map((value: any) => `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}`), + data: labels.map((value: any) => { + switch (this.windowPreference) { + case "2h": + return `${formatDate(value, 'h:mm a', this.locale)}` + case "24h": + return `${formatDate(value, 'h a', this.locale)}` + case "1w": + return `${formatDate(value, 'EEE, MMM d', this.locale)}` + case "1m": + return `${formatDate(value, 'EEE, MMM d', this.locale)}` + case "3m": + return `${formatDate(value, 'MMM d', this.locale)}` + case "6m": + return `${formatDate(value, 'MMM d', this.locale)}` + case "1y": + return `${formatDate(value, 'MMM y', this.locale)}` + case "2y": + return `${formatDate(value, 'MMM y', this.locale)}` + case "3y": + return `${formatDate(value, 'MMM y', this.locale)}` + default: + return `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}` + } + }), } ], yAxis: { From cbd187d06fde9ba74d8c47bd8eef763b043afc37 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 00:04:20 +0900 Subject: [PATCH 03/16] Use `time` for xAxis type and fix the mempool tooltip accordingly --- backend/src/api/statistics.ts | 6 +-- .../mempool-graph/mempool-graph.component.ts | 42 ++++--------------- .../src/app/interfaces/node-api.interface.ts | 2 +- 3 files changed, 13 insertions(+), 37 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index 8aad48e2b..ee6052cdf 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -268,7 +268,7 @@ class Statistics { } private getQueryForDays(div: number, limit: number) { - return `SELECT id, added, unconfirmed_transactions, + return `SELECT id, UNIX_TIMESTAMP(added) as added, unconfirmed_transactions, tx_per_second, vbytes_per_second, vsize_1, @@ -314,7 +314,7 @@ class Statistics { public async $get(id: number): Promise { 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(query, [id]); connection.release(); if (rows[0]) { @@ -328,7 +328,7 @@ class Statistics { public async $list2H(): Promise { 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({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); 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 ce4550759..77aa5f97f 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -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); } @@ -192,8 +192,8 @@ export class MempoolGraphComponent implements OnInit, OnChanges { 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 +233,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { - ${this.vbytesPipe.transform(item.value, 2, 'vB', 'MvB', false)} + ${this.vbytesPipe.transform(item.value[1], 2, 'vB', 'MvB', false)} @@ -257,7 +257,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const titleSum = $localize`Sum`; return `
- ${params[0].axisValue} + ${params[0].axisValueLabel} ${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)} @@ -312,7 +312,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }, xAxis: [ { - type: 'category', + type: 'time', boundaryGap: false, axisLine: { onZero: true }, axisLabel: { @@ -320,30 +320,6 @@ export class MempoolGraphComponent implements OnInit, OnChanges { fontSize: 11, lineHeight: 12, }, - data: labels.map((value: any) => { - switch (this.windowPreference) { - case "2h": - return `${formatDate(value, 'h:mm a', this.locale)}` - case "24h": - return `${formatDate(value, 'h a', this.locale)}` - case "1w": - return `${formatDate(value, 'EEE, MMM d', this.locale)}` - case "1m": - return `${formatDate(value, 'EEE, MMM d', this.locale)}` - case "3m": - return `${formatDate(value, 'MMM d', this.locale)}` - case "6m": - return `${formatDate(value, 'MMM d', this.locale)}` - case "1y": - return `${formatDate(value, 'MMM y', this.locale)}` - case "2y": - return `${formatDate(value, 'MMM y', this.locale)}` - case "3y": - return `${formatDate(value, 'MMM y', this.locale)}` - default: - return `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}` - } - }), } ], yAxis: { @@ -369,7 +345,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 { diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 550f712d9..2cdff2b99 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -1,6 +1,6 @@ export interface OptimizedMempoolStats { id: number; - added: string; + added: number; unconfirmed_transactions: number; tx_per_second: number; vbytes_per_second: number; From 37722fe165869777e87dc2c56e15d51881386d0d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 00:24:10 +0900 Subject: [PATCH 04/16] Remove dead code FeeDistributionGraphComponent --- frontend/src/app/app.module.ts | 2 - .../fee-distribution-graph.component.html | 9 -- .../fee-distribution-graph.component.ts | 83 ------------------- .../mempool-block.component.html | 3 - 4 files changed, 97 deletions(-) delete mode 100644 frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html delete mode 100644 frontend/src/app/components/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 bb6383421..e599293a6 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -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'; @@ -83,7 +82,6 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra MempoolBlocksComponent, FooterComponent, MempoolBlockComponent, - FeeDistributionGraphComponent, IncomingTransactionsGraphComponent, MempoolGraphComponent, LbtcPegsGraphComponent, diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html deleted file mode 100644 index 3465bde35..000000000 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
-
- - -
-
-
-
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts deleted file mode 100644 index 8c90036fd..000000000 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts +++ /dev/null @@ -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, - } - }] - }; - } -} diff --git a/frontend/src/app/components/mempool-block/mempool-block.component.html b/frontend/src/app/components/mempool-block/mempool-block.component.html index d59b3c477..48baa3c23 100644 --- a/frontend/src/app/components/mempool-block/mempool-block.component.html +++ b/frontend/src/app/components/mempool-block/mempool-block.component.html @@ -40,9 +40,6 @@
-
- -
From 41f3f0ab462797b9c2b7593bd32f5f50582d9d30 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 10:38:13 +0900 Subject: [PATCH 05/16] Fix graph data for incoming transaction graphs --- frontend/src/app/components/statistics/statistics.component.ts | 2 +- frontend/src/app/dashboard/dashboard.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts index fb386304d..84513fd3f 100644 --- a/frontend/src/app/components/statistics/statistics.component.ts +++ b/frontend/src/app/components/statistics/statistics.component.ts @@ -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])], }; } diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index ea843ec29..a4c6e51c5 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -286,7 +286,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])], }; } From 5e729373bbd384d890f3bb273da7c0986863063d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 15:26:02 +0900 Subject: [PATCH 06/16] Use date interval so we leave mysql handle the number of days in a month etc --- backend/src/api/statistics.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index ee6052cdf..b6738b296 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -267,7 +267,7 @@ class Statistics { } } - private getQueryForDays(div: number, limit: number) { + private getQueryForDays(div: number, interval: string) { return `SELECT id, UNIX_TIMESTAMP(added) as added, unconfirmed_transactions, tx_per_second, vbytes_per_second, @@ -308,7 +308,11 @@ class Statistics { vsize_1400, vsize_1600, vsize_1800, - vsize_2000 FROM statistics GROUP BY UNIX_TIMESTAMP(added) DIV ${div} ORDER BY id DESC LIMIT ${limit}`; + 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 { @@ -341,7 +345,7 @@ class Statistics { public async $list24H(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(300, 288); // 5m interval + const query = this.getQueryForDays(300, '1 DAY'); // 5m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -354,7 +358,8 @@ class Statistics { public async $list1W(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(1800, 336); // 30m interval + const query = this.getQueryForDays(1800, '1 WEEK'); // 30m interval + await connection.query({ sql: "SET time_zone = '+9:00';", timeout: this.queryTimeout }); const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -367,7 +372,7 @@ class Statistics { public async $list1M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(7200, 372); // 4h interval + const query = this.getQueryForDays(7200, '1 MONTH'); // 2h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -380,7 +385,7 @@ class Statistics { public async $list3M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(21600, 372); // 6h interval + const query = this.getQueryForDays(21600, '3 MONTH'); // 6h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -393,7 +398,7 @@ class Statistics { public async $list6M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(43200, 372); // 12h interval + const query = this.getQueryForDays(43200, '6 MONTH'); // 12h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -406,7 +411,7 @@ class Statistics { public async $list1Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(86400, 365); // 1d interval + const query = this.getQueryForDays(86400, '1 YEAR'); // 1d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -419,7 +424,7 @@ class Statistics { public async $list2Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(172800, 365); // 2d interval + const query = this.getQueryForDays(172800, "2 YEAR"); // 2d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -432,7 +437,7 @@ class Statistics { public async $list3Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(259200, 365); // 3d interval + const query = this.getQueryForDays(259200, "3 YEAR"); // 3d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); From 2b0d543ce742c4853b9b2c6e473d2ac3a8c7b986 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 15:26:14 +0900 Subject: [PATCH 07/16] Delete unused code --- frontend/src/app/dashboard/dashboard.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index a4c6e51c5..7cc6a2aec 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -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([])), From 9e8a741d9712c5efd8372f0340b05a48a52a601c Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 15:26:59 +0900 Subject: [PATCH 08/16] Apply proper datetime format according to choosen time scale and force 2h windowPreference in the dashboard --- .../incoming-transactions-graph.component.ts | 60 ++++++++++--------- .../mempool-graph/mempool-graph.component.ts | 35 +++++++++-- .../app/dashboard/dashboard.component.html | 2 + 3 files changed, 65 insertions(+), 32 deletions(-) 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 b1c2399e1..cb441bac4 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 @@ -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(); } @@ -102,14 +103,41 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { + // Todo - Refactor + let axisValueLabel: string = ""; + switch (this.windowPreference) { + case "2h": + axisValueLabel = `${formatDate(params[0].axisValue, 'h:mm a', this.locale)}`; + break; + case "24h": + axisValueLabel = `${formatDate(params[0].axisValue, 'EEE HH:mm', this.locale)}` + break; + case "1w": + axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:mm', this.locale)}` + break; + case "1m": + case "3m": + case "6m": + axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:00', this.locale)}` + break; + case "1y": + case "2y": + case "3y": + axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d y', this.locale)}` + break; + default: + axisValueLabel = `${formatDate(params[0].axisValue, 'M/d', this.locale)}\n${formatDate(params[0].axisValue, 'H:mm', this.locale)}` + break; + } + const colorSpan = (color: string) => ``; - let itemFormatted = '
' + params[0].axisValue + '
'; + let itemFormatted = '
' + axisValueLabel + '
'; params.map((item: any, index: number) => { if (index < 26) { itemFormatted += `
${colorSpan(item.color)}
-
${item.value} vB/s
+
${item.value[1]} vB/s
`; } }); @@ -117,36 +145,12 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { } }, xAxis: { - type: 'category', + type: 'time', axisLabel: { align: 'center', fontSize: 11, lineHeight: 12 }, - data: this.data.labels.map((value: any) => { - switch (this.windowPreference) { - case "2h": - return `${formatDate(value, 'h:mm a', this.locale)}` - case "24h": - return `${formatDate(value, 'h a', this.locale)}` - case "1w": - return `${formatDate(value, 'EEE, MMM d', this.locale)}` - case "1m": - return `${formatDate(value, 'EEE, MMM d', this.locale)}` - case "3m": - return `${formatDate(value, 'MMM d', this.locale)}` - case "6m": - return `${formatDate(value, 'MMM d', this.locale)}` - case "1y": - return `${formatDate(value, 'MMM y', this.locale)}` - case "2y": - return `${formatDate(value, 'MMM y', this.locale)}` - case "3y": - return `${formatDate(value, 'MMM y', this.locale)}` - default: - return `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}` - } - }), }, yAxis: { type: 'value', 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 77aa5f97f..fb02cd1f2 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -1,7 +1,6 @@ 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 { formatDate, formatNumber } from "@angular/common"; import { OptimizedMempoolStats } from 'src/app/interfaces/node-api.interface'; import { StateService } from 'src/app/services/state.service'; @@ -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(); } @@ -186,6 +186,33 @@ export class MempoolGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { + // Todo - Refactor + let axisValueLabel: string = ""; + switch (this.windowPreference) { + case "2h": + axisValueLabel = `${formatDate(params[0].axisValue, 'h:mm a', this.locale)}`; + break; + case "24h": + axisValueLabel = `${formatDate(params[0].axisValue, 'EEE HH:mm', this.locale)}` + break; + case "1w": + axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:mm', this.locale)}` + break; + case "1m": + case "3m": + case "6m": + axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:00', this.locale)}` + break; + case "1y": + case "2y": + case "3y": + axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d y', this.locale)}` + break; + default: + axisValueLabel = `${formatDate(params[0].axisValue, 'M/d', this.locale)}\n${formatDate(params[0].axisValue, 'H:mm', this.locale)}` + break; + } + const { totalValue, totalValueArray } = this.getTotalValues(params); const itemFormatted = []; let totalParcial = 0; @@ -257,7 +284,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const titleSum = $localize`Sum`; return `
- ${params[0].axisValueLabel} + ${axisValueLabel} ${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)} diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 530c365a0..36c018761 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -54,6 +54,7 @@ [limitFee]="150" [limitFilterFee]="1" [data]="mempoolStats.value?.mempool" + [windowPreferenceOverride]="'2h'" >
@@ -73,6 +74,7 @@
From 7e7dbdbaf26ee3f229ef0db06a66485f84bbe754 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 15:43:20 +0900 Subject: [PATCH 09/16] Remove test code --- backend/src/api/statistics.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index b6738b296..b917baec3 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -359,7 +359,6 @@ class Statistics { try { const connection = await DB.pool.getConnection(); const query = this.getQueryForDays(1800, '1 WEEK'); // 30m interval - await connection.query({ sql: "SET time_zone = '+9:00';", timeout: this.queryTimeout }); const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); From 11577842a275305b26a38e6d1b6901565f5859e1 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 17:10:55 +0900 Subject: [PATCH 10/16] Refactor tooltip formatting into common file and switch to native js localization --- .../incoming-transactions-graph.component.ts | 30 ++--------------- .../mempool-graph/mempool-graph.component.ts | 32 ++----------------- frontend/src/app/shared/graphs.utils.ts | 28 ++++++++++++++++ frontend/src/styles.scss | 2 +- 4 files changed, 34 insertions(+), 58 deletions(-) create mode 100644 frontend/src/app/shared/graphs.utils.ts 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 cb441bac4..a618a2b07 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 @@ -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 } from 'src/app/shared/graphs.utils'; @Component({ selector: 'app-incoming-transactions-graph', @@ -103,33 +103,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { - // Todo - Refactor - let axisValueLabel: string = ""; - switch (this.windowPreference) { - case "2h": - axisValueLabel = `${formatDate(params[0].axisValue, 'h:mm a', this.locale)}`; - break; - case "24h": - axisValueLabel = `${formatDate(params[0].axisValue, 'EEE HH:mm', this.locale)}` - break; - case "1w": - axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:mm', this.locale)}` - break; - case "1m": - case "3m": - case "6m": - axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:00', this.locale)}` - break; - case "1y": - case "2y": - case "3y": - axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d y', this.locale)}` - break; - default: - axisValueLabel = `${formatDate(params[0].axisValue, 'M/d', this.locale)}\n${formatDate(params[0].axisValue, 'H:mm', this.locale)}` - break; - } - + const axisValueLabel: string = formatterXAxis(this.locale, this.windowPreference, params[0].axisValue); const colorSpan = (color: string) => ``; let itemFormatted = '
' + axisValueLabel + '
'; params.map((item: any, index: number) => { 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 fb02cd1f2..e6aec74c2 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnChanges } from '@angular/core'; import { VbytesPipe } from 'src/app/shared/pipes/bytes-pipe/vbytes.pipe'; -import { formatDate, formatNumber } from "@angular/common"; - +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 } from 'src/app/shared/graphs.utils'; @Component({ selector: 'app-mempool-graph', @@ -186,33 +186,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { - // Todo - Refactor - let axisValueLabel: string = ""; - switch (this.windowPreference) { - case "2h": - axisValueLabel = `${formatDate(params[0].axisValue, 'h:mm a', this.locale)}`; - break; - case "24h": - axisValueLabel = `${formatDate(params[0].axisValue, 'EEE HH:mm', this.locale)}` - break; - case "1w": - axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:mm', this.locale)}` - break; - case "1m": - case "3m": - case "6m": - axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d HH:00', this.locale)}` - break; - case "1y": - case "2y": - case "3y": - axisValueLabel = `${formatDate(params[0].axisValue, 'MMM d y', this.locale)}` - break; - default: - axisValueLabel = `${formatDate(params[0].axisValue, 'M/d', this.locale)}\n${formatDate(params[0].axisValue, 'H:mm', this.locale)}` - break; - } - + const axisValueLabel: string = formatterXAxis(this.locale, this.windowPreference, params[0].axisValue); const { totalValue, totalValueArray } = this.getTotalValues(params); const itemFormatted = []; let totalParcial = 0; diff --git a/frontend/src/app/shared/graphs.utils.ts b/frontend/src/app/shared/graphs.utils.ts new file mode 100644 index 000000000..9f5a5d79a --- /dev/null +++ b/frontend/src/app/shared/graphs.utils.ts @@ -0,0 +1,28 @@ +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': + return date.toLocaleTimeString(locale, { month: 'short', day: 'numeric', hour: 'numeric' }); + case '1y': + case '2y': + case '3y': + return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); + } +}; \ No newline at end of file diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index afc16ec52..e870f32e8 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -555,7 +555,7 @@ html:lang(ru) .card-title { } .tx-wrapper-tooltip-chart-advanced { - width: 115px; + width: 140px; .indicator-container { .indicator { margin-right: 5px; From 6e4985602eba2859ddc782a8ecee52867e5bd8dd Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 17:27:52 +0900 Subject: [PATCH 11/16] Increase the number of data to be as close as possible from prod while keeping rounded intervals --- backend/src/api/statistics.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index b917baec3..8ca0eba8f 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -345,7 +345,7 @@ class Statistics { public async $list24H(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(300, '1 DAY'); // 5m interval + const query = this.getQueryForDays(120, '1 DAY'); // 2m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -358,7 +358,7 @@ class Statistics { public async $list1W(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(1800, '1 WEEK'); // 30m interval + const query = this.getQueryForDays(1200, '1 WEEK'); // 20m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -371,7 +371,7 @@ class Statistics { public async $list1M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(7200, '1 MONTH'); // 2h interval + const query = this.getQueryForDays(3600, '1 MONTH'); // 1h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -384,7 +384,7 @@ class Statistics { public async $list3M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(21600, '3 MONTH'); // 6h interval + const query = this.getQueryForDays(14400, '3 MONTH'); // 4h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -397,7 +397,7 @@ class Statistics { public async $list6M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(43200, '6 MONTH'); // 12h interval + const query = this.getQueryForDays(28800, '6 MONTH'); // 8h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -410,7 +410,7 @@ class Statistics { public async $list1Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(86400, '1 YEAR'); // 1d interval + const query = this.getQueryForDays(54000, '1 YEAR'); // 15h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -423,7 +423,7 @@ class Statistics { public async $list2Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(172800, "2 YEAR"); // 2d interval + const query = this.getQueryForDays(86400, "2 YEAR"); // 1d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -436,7 +436,7 @@ class Statistics { public async $list3Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(259200, "3 YEAR"); // 3d interval + const query = this.getQueryForDays(172800, "3 YEAR"); // 2d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); From c9f5002dc2b659aaf1157e6026a39594093f3a8b Mon Sep 17 00:00:00 2001 From: nymkappa Date: Sat, 11 Dec 2021 19:15:20 +0900 Subject: [PATCH 12/16] Use avg() mysql value for timespan between [24h, 6m] --- backend/src/api/statistics.ts | 59 ++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index 8ca0eba8f..fcd28d40e 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -267,6 +267,55 @@ class Statistics { } } + 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, @@ -345,7 +394,7 @@ class Statistics { public async $list24H(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, '1 DAY'); // 2m interval + const query = this.getQueryForDaysAvg(120, '1 DAY'); // 2m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -358,7 +407,7 @@ class Statistics { public async $list1W(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(1200, '1 WEEK'); // 20m interval + const query = this.getQueryForDaysAvg(1200, '1 WEEK'); // 20m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -371,7 +420,7 @@ class Statistics { public async $list1M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(3600, '1 MONTH'); // 1h interval + const query = this.getQueryForDaysAvg(3600, '1 MONTH'); // 1h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -384,7 +433,7 @@ class Statistics { public async $list3M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(14400, '3 MONTH'); // 4h interval + const query = this.getQueryForDaysAvg(14400, '3 MONTH'); // 4h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -397,7 +446,7 @@ class Statistics { public async $list6M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(28800, '6 MONTH'); // 8h interval + const query = this.getQueryForDaysAvg(28800, '6 MONTH'); // 8h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); From aee319ed518f3673c5cf2e0a6f4f691ddec8a08a Mon Sep 17 00:00:00 2001 From: nymkappa Date: Mon, 13 Dec 2021 11:56:24 +0900 Subject: [PATCH 13/16] Initialize graphWindowPreference in localstorage properly --- frontend/src/app/services/storage.service.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/frontend/src/app/services/storage.service.ts b/frontend/src/app/services/storage.service.ts index c7595b404..7494784f6 100644 --- a/frontend/src/app/services/storage.service.ts +++ b/frontend/src/app/services/storage.service.ts @@ -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); From cf0af20947fa6869e7839c745f8b403250eb1a75 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Mon, 13 Dec 2021 14:27:05 +0900 Subject: [PATCH 14/16] Hide xaxis label overlapping - Show current day/month/year below the chart for self better self containing overview --- .../incoming-transactions-graph.component.ts | 31 +++++++++++++------ .../mempool-graph/mempool-graph.component.ts | 12 +++++-- frontend/src/app/shared/graphs.utils.ts | 22 +++++++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) 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 a618a2b07..2f4404249 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,7 +2,7 @@ import { Component, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnInit } import { EChartsOption } from 'echarts'; import { OnChanges } from '@angular/core'; import { StorageService } from 'src/app/services/storage.service'; -import { formatterXAxis } from 'src/app/shared/graphs.utils'; +import { formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils'; @Component({ selector: 'app-incoming-transactions-graph', @@ -78,6 +78,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { type: 'slider', brushSelect: false, realtime: true, + bottom: 0, selectedDataBackground: { lineStyle: { color: '#fff', @@ -86,7 +87,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { areaStyle: { opacity: 0, } - } + }, }], tooltip: { trigger: 'axis', @@ -118,14 +119,24 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { return `
${itemFormatted}
`; } }, - xAxis: { - type: 'time', - axisLabel: { - align: 'center', - fontSize: 11, - lineHeight: 12 - }, - }, + 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: { 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 e6aec74c2..75175c1a5 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -6,7 +6,7 @@ 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 } from 'src/app/shared/graphs.utils'; +import { formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils'; @Component({ selector: 'app-mempool-graph', @@ -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 = []; @@ -313,13 +313,21 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }, xAxis: [ { + 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], }, } ], diff --git a/frontend/src/app/shared/graphs.utils.ts b/frontend/src/app/shared/graphs.utils.ts index 9f5a5d79a..0380fa964 100644 --- a/frontend/src/app/shared/graphs.utils.ts +++ b/frontend/src/app/shared/graphs.utils.ts @@ -25,4 +25,26 @@ export const formatterXAxis = ( 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; + } }; \ No newline at end of file From 92d745168c58ac626fd3b7cdda4ba742e6583c50 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Mon, 13 Dec 2021 14:31:34 +0900 Subject: [PATCH 15/16] Doubled the data points for 1W and 3Y to improve resolution --- backend/src/api/statistics.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index fcd28d40e..2613ca676 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -407,7 +407,7 @@ class Statistics { public async $list1W(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDaysAvg(1200, '1 WEEK'); // 20m interval + const query = this.getQueryForDaysAvg(600, '1 WEEK'); // 10m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -485,7 +485,7 @@ class Statistics { public async $list3Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(172800, "3 YEAR"); // 2d interval + const query = this.getQueryForDays(86400, "3 YEAR"); // 1d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); From 28d3f190ff23cf0a7a9f2c784f468e8ec48dfa3c Mon Sep 17 00:00:00 2001 From: nymkappa Date: Tue, 14 Dec 2021 16:33:17 +0900 Subject: [PATCH 16/16] Update graph tick intervals - Hide label in zoom component - Show hour on 1y graphs --- backend/src/api/statistics.ts | 4 ++-- .../incoming-transactions-graph.component.ts | 1 + .../app/components/mempool-graph/mempool-graph.component.ts | 1 + frontend/src/app/shared/graphs.utils.ts | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index 2613ca676..d1784f937 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -446,7 +446,7 @@ class Statistics { public async $list6M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDaysAvg(28800, '6 MONTH'); // 8h interval + const query = this.getQueryForDaysAvg(21600, '6 MONTH'); // 6h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -459,7 +459,7 @@ class Statistics { public async $list1Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(54000, '1 YEAR'); // 15h interval + const query = this.getQueryForDays(43200, '1 YEAR'); // 12h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); 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 2f4404249..4f982a269 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 @@ -74,6 +74,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { maxSpan: 100, minSpan: 10, }, { + showDetail: false, show: (this.template === 'advanced') ? true : false, type: 'slider', brushSelect: false, 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 75175c1a5..35dacbe26 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -289,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, diff --git a/frontend/src/app/shared/graphs.utils.ts b/frontend/src/app/shared/graphs.utils.ts index 0380fa964..51f3b3f3f 100644 --- a/frontend/src/app/shared/graphs.utils.ts +++ b/frontend/src/app/shared/graphs.utils.ts @@ -19,8 +19,8 @@ export const formatterXAxis = ( case '1m': case '3m': case '6m': - return date.toLocaleTimeString(locale, { month: 'short', day: 'numeric', hour: 'numeric' }); 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' });