From 48a0a6c7e3202bb64f16630fb3518a50a5b2138d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Wed, 10 Aug 2022 15:09:34 +0200 Subject: [PATCH 01/14] Convert short_id to integer id with clightning backend before returning the graph --- backend/src/api/common.ts | 4 ---- backend/src/api/explorer/channels.api.ts | 2 +- backend/src/api/lightning/clightning/clightning-convert.ts | 4 ++-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index 410d34a01..c97d02ba2 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -202,10 +202,6 @@ export class Common { /** Decodes a channel id returned by lnd as uint64 to a short channel id */ static channelIntegerIdToShortId(id: string): string { - if (config.LIGHTNING.BACKEND === 'cln') { - return id; - } - const n = BigInt(id); return [ n >> 40n, // nth block diff --git a/backend/src/api/explorer/channels.api.ts b/backend/src/api/explorer/channels.api.ts index 55043197d..072449d60 100644 --- a/backend/src/api/explorer/channels.api.ts +++ b/backend/src/api/explorer/channels.api.ts @@ -420,7 +420,7 @@ class ChannelsApi { const result = await DB.query(` UPDATE channels SET status = 0 - WHERE short_id NOT IN ( + WHERE id NOT IN ( ${graphChannelsIds.map(id => `"${id}"`).join(',')} ) AND status != 2 diff --git a/backend/src/api/lightning/clightning/clightning-convert.ts b/backend/src/api/lightning/clightning/clightning-convert.ts index 5df51aadc..2bdde31d3 100644 --- a/backend/src/api/lightning/clightning/clightning-convert.ts +++ b/backend/src/api/lightning/clightning/clightning-convert.ts @@ -90,7 +90,7 @@ async function buildFullChannel(clChannelA: any, clChannelB: any): Promise Date: Wed, 10 Aug 2022 16:42:01 +0200 Subject: [PATCH 02/14] Disable country highlight - Update node styling --- .../nodes-channels-map.component.ts | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts index b88621bba..1751a0b1b 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts @@ -146,7 +146,7 @@ export class NodesChannelsMap implements OnInit, OnDestroy { center: this.center, zoom: this.zoom, tooltip: { - show: true + show: false }, map: 'world', roam: this.style === 'widget' ? false : true, @@ -157,6 +157,9 @@ export class NodesChannelsMap implements OnInit, OnDestroy { scaleLimit: { min: 1.3, max: 100000, + }, + emphasis: { + disabled: true, } }, series: [ @@ -169,6 +172,7 @@ export class NodesChannelsMap implements OnInit, OnDestroy { geoIndex: 0, symbolSize: 4, tooltip: { + show: true, backgroundColor: 'rgba(17, 19, 31, 1)', borderRadius: 4, shadowColor: 'rgba(0, 0, 0, 0.5)', @@ -185,12 +189,12 @@ export class NodesChannelsMap implements OnInit, OnDestroy { }, itemStyle: { color: 'white', - borderColor: 'black', - borderWidth: 2, opacity: 1, + borderColor: 'black', + borderWidth: 0, }, blendMode: 'lighter', - zlevel: 1, + zlevel: 2, }, { large: true, @@ -209,7 +213,7 @@ export class NodesChannelsMap implements OnInit, OnDestroy { tooltip: { show: false, }, - zlevel: 2, + zlevel: 1, } ] }; @@ -250,12 +254,19 @@ export class NodesChannelsMap implements OnInit, OnDestroy { series: this.chartOptions.series }; + let nodeBorder = 0; + if (this.chartInstance.getOption().geo[0].zoom > 5000) { + nodeBorder = 2; + } + + chartOptions.series[0].itemStyle.borderWidth = nodeBorder; + chartOptions.series[0].symbolSize += e.zoom > 1 ? speed * 15 : -speed * 15; + chartOptions.series[0].symbolSize = Math.max(4, Math.min(7, chartOptions.series[0].symbolSize)); + chartOptions.series[1].lineStyle.opacity += e.zoom > 1 ? speed : -speed; chartOptions.series[1].lineStyle.width += e.zoom > 1 ? speed : -speed; - chartOptions.series[0].symbolSize += e.zoom > 1 ? speed * 10 : -speed * 10; chartOptions.series[1].lineStyle.opacity = Math.max(0.05, Math.min(0.5, chartOptions.series[1].lineStyle.opacity)); chartOptions.series[1].lineStyle.width = Math.max(0.5, Math.min(1, chartOptions.series[1].lineStyle.width)); - chartOptions.series[0].symbolSize = Math.max(4, Math.min(5.5, chartOptions.series[0].symbolSize)); this.chartInstance.setOption(chartOptions); }); From dc7231537f7c2342c818f80f867e5bc3d6bde03e Mon Sep 17 00:00:00 2001 From: nymkappa Date: Wed, 10 Aug 2022 16:58:29 +0200 Subject: [PATCH 03/14] Refactor channel id conversion utils --- backend/src/api/common.ts | 17 ++++++++++++----- .../lightning/clightning/clightning-convert.ts | 13 +++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index c97d02ba2..8d9de53c9 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -1,6 +1,5 @@ import { CpfpInfo, TransactionExtended, TransactionStripped } from '../mempool.interfaces'; import config from '../config'; -import { convertChannelId } from './lightning/clightning/clightning-convert'; export class Common { static nativeAssetId = config.MEMPOOL.NETWORK === 'liquidtestnet' ? '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49' @@ -193,15 +192,23 @@ export class Common { date.setUTCMilliseconds(0); } - static channelShortIdToIntegerId(id: string): string { - if (config.LIGHTNING.BACKEND === 'lnd') { - return id; + static channelShortIdToIntegerId(channelId: string): string { + if (channelId.indexOf('x') === -1) { // Already an integer id + return channelId; } - return convertChannelId(id); + if (channelId.indexOf('/') !== -1) { // Topology import + channelId = channelId.slice(0, -2); + } + const s = channelId.split('x').map(part => BigInt(part)); + return ((s[0] << 40n) | (s[1] << 16n) | s[2]).toString(); } /** Decodes a channel id returned by lnd as uint64 to a short channel id */ static channelIntegerIdToShortId(id: string): string { + if (id.indexOf('x') !== -1) { // Already a short id + return id; + } + const n = BigInt(id); return [ n >> 40n, // nth block diff --git a/backend/src/api/lightning/clightning/clightning-convert.ts b/backend/src/api/lightning/clightning/clightning-convert.ts index 2bdde31d3..15d8d8766 100644 --- a/backend/src/api/lightning/clightning/clightning-convert.ts +++ b/backend/src/api/lightning/clightning/clightning-convert.ts @@ -1,6 +1,7 @@ import { ILightningApi } from '../lightning-api.interface'; import FundingTxFetcher from '../../../tasks/lightning/sync-tasks/funding-tx-fetcher'; import logger from '../../../logger'; +import { Common } from '../../common'; /** * Convert a clightning "listnode" entry to a lnd node entry @@ -70,14 +71,6 @@ export async function convertAndmergeBidirectionalChannels(clChannels: any[]): P return consolidatedChannelList; } -export function convertChannelId(channelId): string { - if (channelId.indexOf('/') !== -1) { - channelId = channelId.slice(0, -2); - } - const s = channelId.split('x').map(part => BigInt(part)); - return ((s[0] << 40n) | (s[1] << 16n) | s[2]).toString(); -} - /** * Convert two clightning "getchannels" entries into a full a lnd "describegraph.edges" format * In this case, clightning knows the channel policy for both nodes @@ -90,7 +83,7 @@ async function buildFullChannel(clChannelA: any, clChannelB: any): Promise Date: Wed, 10 Aug 2022 17:03:11 +0200 Subject: [PATCH 04/14] Fix channel rendering issue --- .../nodes-channels-map/nodes-channels-map.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts index 43da510f0..c055ad415 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts @@ -197,7 +197,6 @@ export class NodesChannelsMap implements OnInit, OnDestroy { series: [ { large: true, - progressive: 200, type: 'scatter', data: nodes, coordinateSystem: 'geo', @@ -228,7 +227,7 @@ export class NodesChannelsMap implements OnInit, OnDestroy { zlevel: 1, }, { - large: true, + large: false, progressive: 200, silent: true, type: 'lines', From 2aaa392bf5b807667155e2d6d10c700aee7ed873 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Wed, 10 Aug 2022 12:33:22 -0400 Subject: [PATCH 05/14] Add nofollow to all api link examples --- frontend/src/app/docs/api-docs/api-docs.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/docs/api-docs/api-docs.component.html b/frontend/src/app/docs/api-docs/api-docs.component.html index bae5dfd05..ec7e5589d 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.html +++ b/frontend/src/app/docs/api-docs/api-docs.component.html @@ -42,16 +42,16 @@
Endpoint
- {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} + {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} - {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} + {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} - {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} + {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }}
{{ item.httpRequestMethod }} {{ item.urlString }}
From 5b4d394039989042280abc4ebe778192dc8c88a1 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Wed, 10 Aug 2022 15:17:47 -0400 Subject: [PATCH 06/14] Remove doc scroll listener after navigating away --- frontend/src/app/docs/api-docs/api-docs.component.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/docs/api-docs/api-docs.component.ts b/frontend/src/app/docs/api-docs/api-docs.component.ts index 260a701ea..ed0ecb0a2 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.ts +++ b/frontend/src/app/docs/api-docs/api-docs.component.ts @@ -50,9 +50,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { document.getElementById( this.route.snapshot.fragment ).scrollIntoView(); } } - window.addEventListener('scroll', function() { - that.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative"; - }, { passive: true} ); + window.addEventListener('scroll', that.onDocScroll, { passive: true }); }, 1 ); } @@ -87,6 +85,14 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { }); } + ngOnDestroy(): void { + window.removeEventListener('scroll', this.onDocScroll); + } + + onDocScroll() { + this.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative"; + } + anchorLinkClick( event: any ) { let targetId = ""; if( event.target.nodeName === "A" ) { From 1d71e26a12c1c1875bf5015643139d555b4be380 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 11 Aug 2022 10:19:13 +0200 Subject: [PATCH 07/14] Add ISP chart in the dashboard - Fix mobile layout - Start polishing --- backend/src/api/explorer/nodes.api.ts | 2 +- backend/src/api/explorer/nodes.routes.ts | 2 +- .../pool-ranking/pool-ranking.component.html | 6 +- .../lightning-dashboard.component.html | 24 +++- .../lightning-dashboard.component.scss | 34 +++++- .../nodes-channels-map.component.scss | 13 ++- .../nodes-channels-map.component.ts | 12 +- .../nodes-list/nodes-list.component.html | 8 +- .../nodes-list/nodes-list.component.scss | 11 ++ .../nodes-list/nodes-list.component.ts | 1 + .../nodes-per-isp-chart.component.html | 64 +++++++++-- .../nodes-per-isp-chart.component.scss | 108 +++++++++++++++++- .../nodes-per-isp-chart.component.ts | 58 +++++++--- .../lightning-statistics-chart.component.scss | 3 +- 14 files changed, 292 insertions(+), 54 deletions(-) diff --git a/backend/src/api/explorer/nodes.api.ts b/backend/src/api/explorer/nodes.api.ts index d4857a3a4..2d838524e 100644 --- a/backend/src/api/explorer/nodes.api.ts +++ b/backend/src/api/explorer/nodes.api.ts @@ -168,7 +168,7 @@ class NodesApi { } } - public async $getNodesISP(groupBy: string, showTor: boolean) { + public async $getNodesISPRanking(groupBy: string, showTor: boolean) { try { const orderBy = groupBy === 'capacity' ? `CAST(SUM(capacity) as INT)` : `COUNT(DISTINCT nodes.public_key)`; diff --git a/backend/src/api/explorer/nodes.routes.ts b/backend/src/api/explorer/nodes.routes.ts index a850b6a09..5e0f95acb 100644 --- a/backend/src/api/explorer/nodes.routes.ts +++ b/backend/src/api/explorer/nodes.routes.ts @@ -79,7 +79,7 @@ class NodesRoutes { return; } - const nodesPerAs = await nodesApi.$getNodesISP(groupBy, showTor); + const nodesPerAs = await nodesApi.$getNodesISPRanking(groupBy, showTor); res.header('Pragma', 'public'); res.header('Cache-control', 'public'); diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.html b/frontend/src/app/components/pool-ranking/pool-ranking.component.html index ae1bb2eb2..1888b3eee 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.html +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.html @@ -76,10 +76,8 @@
-
-
-
+
diff --git a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html index 999183e09..3fbbaa4e2 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html @@ -4,6 +4,7 @@
+
Network Statistics  @@ -17,6 +18,7 @@
+
Channels Statistics  @@ -30,18 +32,28 @@
-
+ +
+
+
+ + +
+
+
+ +
-
-
+
+ @@ -52,7 +64,7 @@
Top Capacity Nodes
- +
@@ -62,7 +74,7 @@
Most Connected Nodes
- +
diff --git a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.scss b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.scss index 4fdadd57b..303591974 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.scss +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.scss @@ -14,6 +14,13 @@ background-color: #1d1f31; } +.graph-card { + height: 100%; + @media (min-width: 992px) { + height: 385px; + } +} + .card-title { font-size: 1rem; color: #4a68b9; @@ -22,9 +29,6 @@ color: #4a68b9; } -.card-body { - padding: 1.25rem 1rem 0.75rem 1rem; -} .card-body.pool-ranking { padding: 1.25rem 0.25rem 0.75rem 0.25rem; } @@ -32,6 +36,21 @@ font-size: 22px; } +#blockchain-container { + position: relative; + overflow-x: scroll; + overflow-y: hidden; + scrollbar-width: none; + -ms-overflow-style: none; +} + +#blockchain-container::-webkit-scrollbar { + display: none; +} + +.fade-border { + -webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 80%, transparent 100%) +} .main-title { position: relative; @@ -45,7 +64,7 @@ } .more-padding { - padding: 18px; + padding: 24px 20px !important; } .card-wrapper { @@ -78,3 +97,10 @@ .card-text { font-size: 22px; } + +.title-link, .title-link:hover, .title-link:focus, .title-link:active { + display: block; + margin-bottom: 10px; + text-decoration: none; + color: inherit; +} \ No newline at end of file diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss index 7e6b9f050..578bffc3a 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.scss @@ -30,21 +30,28 @@ } .widget { - width: 99vw; + width: 90vw; + margin-left: auto; + margin-right: auto; height: 250px; -webkit-mask: linear-gradient(0deg, #11131f00 5%, #11131fff 25%); + @media (max-width: 767.98px) { + width: 100vw; + } } .widget > .chart { - -webkit-mask: linear-gradient(180deg, #11131f00 0%, #11131fff 20%); min-height: 250px; + -webkit-mask: linear-gradient(180deg, #11131f00 0%, #11131fff 20%); + @media (max-width: 767.98px) { + padding-bottom: 0px; + } } .chart { min-height: 500px; width: 100%; height: 100%; - padding-right: 10px; @media (max-width: 992px) { padding-bottom: 25px; } diff --git a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts index 43da510f0..92c566156 100644 --- a/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts +++ b/frontend/src/app/lightning/nodes-channels-map/nodes-channels-map.component.ts @@ -8,6 +8,7 @@ import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url. import { StateService } from 'src/app/services/state.service'; import { EChartsOption, registerMap } from 'echarts'; import 'echarts-gl'; +import { isMobile } from 'src/app/shared/common.utils'; @Component({ selector: 'app-nodes-channels-map', @@ -50,8 +51,15 @@ export class NodesChannelsMap implements OnInit, OnDestroy { ngOnInit(): void { this.center = this.style === 'widget' ? [0, 40] : [0, 5]; - this.zoom = this.style === 'widget' ? 3.5 : 1.3; - + this.zoom = 1.3; + if (this.style === 'widget' && !isMobile()) { + this.zoom = 3.5; + } + if (this.style === 'widget' && isMobile()) { + this.zoom = 1.4; + this.center = [0, 10]; + } + if (this.style === 'graph') { this.seoService.setTitle($localize`Lightning nodes channels world map`); } diff --git a/frontend/src/app/lightning/nodes-list/nodes-list.component.html b/frontend/src/app/lightning/nodes-list/nodes-list.component.html index 65a7a558a..d21f0b30a 100644 --- a/frontend/src/app/lightning/nodes-list/nodes-list.component.html +++ b/frontend/src/app/lightning/nodes-list/nodes-list.component.html @@ -3,18 +3,18 @@ - - + + - - diff --git a/frontend/src/app/lightning/nodes-list/nodes-list.component.scss b/frontend/src/app/lightning/nodes-list/nodes-list.component.scss index e69de29bb..85a1339ea 100644 --- a/frontend/src/app/lightning/nodes-list/nodes-list.component.scss +++ b/frontend/src/app/lightning/nodes-list/nodes-list.component.scss @@ -0,0 +1,11 @@ +.capacity.mobile-channels { + @media (max-width: 767.98px) { + display: none; + } +} + +.channels.mobile-capacity { + @media (max-width: 767.98px) { + display: none; + } +} \ No newline at end of file diff --git a/frontend/src/app/lightning/nodes-list/nodes-list.component.ts b/frontend/src/app/lightning/nodes-list/nodes-list.component.ts index d6d05833e..9b9e2d594 100644 --- a/frontend/src/app/lightning/nodes-list/nodes-list.component.ts +++ b/frontend/src/app/lightning/nodes-list/nodes-list.component.ts @@ -9,6 +9,7 @@ import { Observable } from 'rxjs'; }) export class NodesListComponent implements OnInit { @Input() nodes$: Observable; + @Input() show: string; constructor() { } diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html index 23f54bbba..5e14ac67b 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html @@ -1,6 +1,29 @@ -
+
-
+
+
+
+
Tagged ISPs
+

+ {{ stats.taggedISP }} +

+
+
+
Tagged capacity
+

+ +

+
+
+
Tagged nodes
+

+ {{ stats.taggedNodeCount }} +

+
+
+
+ +
Lightning nodes per ISP
-
-
-
-
+
+
-
+
-
AliasCapacityChannelsCapacityChannels
{{ node.alias }} + + {{ node.channels | number }}
+
@@ -39,7 +60,7 @@ - +
Rank
{{ asEntry.rank }} {{ asEntry.name }} @@ -54,3 +75,26 @@ + + +
+
+
Tagged ISPs
+

+ +

+
+
+
Tagged capacity
+

+ +

+
+
+
Tagged nodes
+

+ +

+
+
+
diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss index 10ad39372..874d901b2 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss @@ -22,7 +22,40 @@ max-height: 400px; @media (max-width: 767.98px) { max-height: 230px; - margin-top: -35px; + margin-top: -40px; + } +} +.chart-widget { + width: 100%; + height: 100%; + height: 240px; + @media (max-width: 485px) { + max-height: 200px; + } +} + +.formRadioGroup { + margin-top: 6px; + display: flex; + flex-direction: column; + @media (min-width: 991px) { + position: relative; + top: -65px; + } + @media (min-width: 830px) and (max-width: 991px) { + position: relative; + top: 0px; + } + @media (min-width: 830px) { + flex-direction: row; + float: right; + margin-top: 0px; + } + .btn-sm { + font-size: 9px; + @media (min-width: 830px) { + font-size: 14px; + } } } @@ -35,6 +68,79 @@ }; } +@media (max-width: 767.98px) { + .pools-table th, + .pools-table td { + padding: .3em !important; + } +} + +.loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; +} + +.pool-distribution { + min-height: 56px; + display: block; + @media (min-width: 485px) { + display: flex; + flex-direction: row; + } + h5 { + margin-bottom: 5px; + } + .item { + max-width: 160px; + width: 50%; + display: inline-block; + margin: 0px auto 20px; + &:nth-child(2) { + order: 2; + @media (min-width: 485px) { + order: 3; + } + } + &:nth-child(3) { + width: 50%; + order: 3; + @media (min-width: 485px) { + order: 2; + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + .card-title { + font-size: 1rem; + color: #4a68b9; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .card-text { + font-size: 18px; + span { + color: #ffffff66; + font-size: 12px; + } + } + } +} + +.skeleton-loader { + width: 100%; + display: block; + max-width: 80px; + margin: 15px auto 3px; +} + .rank { width: 15%; @media (max-width: 576px) { diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts index 6b9d41e74..cd8a72884 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.ts @@ -1,11 +1,12 @@ -import { ChangeDetectionStrategy, Component, OnInit, HostBinding, NgZone } from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnInit, HostBinding, NgZone, Input } from '@angular/core'; import { Router } from '@angular/router'; import { EChartsOption, PieSeriesOption } from 'echarts'; -import { combineLatest, map, Observable, share, Subject, switchMap, tap } from 'rxjs'; +import { combineLatest, map, Observable, share, startWith, Subject, switchMap, tap } from 'rxjs'; import { chartColors } from 'src/app/app.constants'; import { ApiService } from 'src/app/services/api.service'; import { SeoService } from 'src/app/services/seo.service'; import { StateService } from 'src/app/services/state.service'; +import { isMobile } from 'src/app/shared/common.utils'; import { download } from 'src/app/shared/graphs.utils'; import { AmountShortenerPipe } from 'src/app/shared/pipes/amount-shortener.pipe'; import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe'; @@ -17,6 +18,8 @@ import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url. changeDetection: ChangeDetectionStrategy.OnPush, }) export class NodesPerISPChartComponent implements OnInit { + @Input() widget: boolean = false; + isLoading = true; chartOptions: EChartsOption = {}; chartInitOptions = { @@ -46,7 +49,11 @@ export class NodesPerISPChartComponent implements OnInit { this.seoService.setTitle($localize`Lightning nodes per ISP`); this.showTorObservable$ = this.showTorSubject.asObservable(); - this.nodesPerAsObservable$ = combineLatest([this.groupBySubject, this.showTorSubject]) + + this.nodesPerAsObservable$ = combineLatest([ + this.groupBySubject.pipe(startWith(false)), + this.showTorSubject.pipe(startWith(false)), + ]) .pipe( switchMap((selectedFilters) => { return this.apiService.getNodesPerAs( @@ -62,23 +69,41 @@ export class NodesPerISPChartComponent implements OnInit { for (let i = 0; i < data.length; ++i) { data[i].rank = i + 1; } - return data.slice(0, 100); + return { + taggedISP: data.length, + taggedCapacity: data.reduce((partialSum, isp) => partialSum + isp.capacity, 0), + taggedNodeCount: data.reduce((partialSum, isp) => partialSum + isp.count, 0), + data: data.slice(0, 100), + }; }) ); }), share() ); + + if (this.widget) { + this.showTorSubject.next(false); + this.groupBySubject.next(false); + } } generateChartSerieData(as): PieSeriesOption[] { - const shareThreshold = this.isMobile() ? 2 : 0.5; + let shareThreshold = 0.5; + if (this.widget && isMobile() || isMobile()) { + shareThreshold = 1; + } else if (this.widget) { + shareThreshold = 0.75; + } + const data: object[] = []; let totalShareOther = 0; let totalNodeOther = 0; let edgeDistance: string | number = '10%'; - if (this.isMobile()) { + if (isMobile() && this.widget) { edgeDistance = 0; + } else if (isMobile() && !this.widget || this.widget) { + edgeDistance = 10; } as.forEach((as) => { @@ -92,15 +117,16 @@ export class NodesPerISPChartComponent implements OnInit { color: as.ispId === null ? '#7D4698' : undefined, }, value: as.share, - name: as.name + (this.isMobile() ? `` : ` (${as.share}%)`), + name: as.name + (isMobile() || this.widget ? `` : ` (${as.share}%)`), label: { overflow: 'truncate', + width: isMobile() ? 75 : this.widget ? 125 : 250, color: '#b1b1b1', alignTo: 'edge', edgeDistance: edgeDistance, }, tooltip: { - show: !this.isMobile(), + show: !isMobile(), backgroundColor: 'rgba(17, 19, 31, 1)', borderRadius: 4, shadowColor: 'rgba(0, 0, 0, 0.5)', @@ -125,7 +151,7 @@ export class NodesPerISPChartComponent implements OnInit { color: 'grey', }, value: totalShareOther, - name: 'Other' + (this.isMobile() ? `` : ` (${totalShareOther.toFixed(2)}%)`), + name: 'Other' + (isMobile() || this.widget ? `` : ` (${totalShareOther.toFixed(2)}%)`), label: { overflow: 'truncate', color: '#b1b1b1', @@ -153,7 +179,7 @@ export class NodesPerISPChartComponent implements OnInit { prepareChartOptions(as): void { let pieSize = ['20%', '80%']; // Desktop - if (this.isMobile()) { + if (isMobile() && !this.widget) { pieSize = ['15%', '60%']; } @@ -177,8 +203,8 @@ export class NodesPerISPChartComponent implements OnInit { lineStyle: { width: 2, }, - length: this.isMobile() ? 1 : 20, - length2: this.isMobile() ? 1 : undefined, + length: isMobile() ? 1 : 20, + length2: isMobile() ? 1 : undefined, }, label: { fontSize: 14, @@ -204,10 +230,6 @@ export class NodesPerISPChartComponent implements OnInit { }; } - isMobile(): boolean { - return (window.innerWidth <= 767.98); - } - onChartInit(ec): void { if (this.chartInstance !== undefined) { return; @@ -244,5 +266,9 @@ export class NodesPerISPChartComponent implements OnInit { onGroupToggleStatusChanged(e): void { this.groupBySubject.next(e); } + + isEllipsisActive(e) { + return (e.offsetWidth < e.scrollWidth); + } } diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss index fa044a4d6..5f59539e3 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss @@ -51,8 +51,7 @@ } .chart-widget { width: 100%; - height: 100%; - max-height: 270px; + height: 320px; } .formRadioGroup { From 7e356ef0a078dd463519f226ecf668e85886a088 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 11 Aug 2022 16:51:09 +0200 Subject: [PATCH 08/14] Fix recursive call in LN network updater --- backend/src/tasks/lightning/network-sync.service.ts | 2 -- backend/src/tasks/lightning/stats-updater.service.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/tasks/lightning/network-sync.service.ts b/backend/src/tasks/lightning/network-sync.service.ts index b87c63031..1fdd77361 100644 --- a/backend/src/tasks/lightning/network-sync.service.ts +++ b/backend/src/tasks/lightning/network-sync.service.ts @@ -107,8 +107,6 @@ class NetworkSyncService { } catch (e) { logger.err(`Cannot update channel list. Reason: ${(e instanceof Error ? e.message : e)}`); } - - setTimeout(() => { this.$runTasks(); }, 1000 * config.LIGHTNING.STATS_REFRESH_INTERVAL); } // This method look up the creation date of the earliest channel of the node diff --git a/backend/src/tasks/lightning/stats-updater.service.ts b/backend/src/tasks/lightning/stats-updater.service.ts index ecb056859..9e6e5bd82 100644 --- a/backend/src/tasks/lightning/stats-updater.service.ts +++ b/backend/src/tasks/lightning/stats-updater.service.ts @@ -25,7 +25,7 @@ class LightningStatsUpdater { const date = new Date(); Common.setDateMidnight(date); const networkGraph = await lightningApi.$getNetworkGraph(); - LightningStatsImporter.computeNetworkStats(date.getTime() / 1000, networkGraph); + await LightningStatsImporter.computeNetworkStats(date.getTime() / 1000, networkGraph); logger.info(`Updated latest network stats`); } From 786cd85c74ba7a52cf88c0064c51215ebee95774 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Wed, 10 Aug 2022 14:59:28 -0400 Subject: [PATCH 09/14] Avoid linking cpfp link api examples --- frontend/src/app/docs/api-docs/api-docs.component.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/docs/api-docs/api-docs.component.html b/frontend/src/app/docs/api-docs/api-docs.component.html index ec7e5589d..f106c4bc5 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.html +++ b/frontend/src/app/docs/api-docs/api-docs.component.html @@ -46,12 +46,14 @@ - {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} + {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} +

{{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }}

- {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} + {{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }} +

{{ item.httpRequestMethod }} {{ baseNetworkUrl }}/api{{ item.urlString }}

{{ item.httpRequestMethod }} {{ item.urlString }}
From 329e9aa0346b7da328be3bf2a3aabc2bc6926494 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 12 Aug 2022 13:27:43 +0400 Subject: [PATCH 10/14] Fixing broken Matomo och bisq and liquid --- .../src/app/services/enterprise.service.ts | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/services/enterprise.service.ts b/frontend/src/app/services/enterprise.service.ts index 41a6194a1..8f86d28a5 100644 --- a/frontend/src/app/services/enterprise.service.ts +++ b/frontend/src/app/services/enterprise.service.ts @@ -24,16 +24,16 @@ export class EnterpriseService { this.subdomain = subdomain; this.fetchSubdomainInfo(); this.disableSubnetworks(); - } else if (document.location.hostname === 'mempool.space') { + } else { this.insertMatomo(); } } - getSubdomain() { + getSubdomain(): string { return this.subdomain; } - disableSubnetworks() { + disableSubnetworks(): void { this.stateService.env.TESTNET_ENABLED = false; this.stateService.env.LIQUID_ENABLED = false; this.stateService.env.LIQUID_TESTNET_ENABLED = false; @@ -41,7 +41,7 @@ export class EnterpriseService { this.stateService.env.BISQ_ENABLED = false; } - fetchSubdomainInfo() { + fetchSubdomainInfo(): void { this.apiService.getEnterpriseInfo$(this.subdomain).subscribe((info) => { this.info = info; this.insertMatomo(info.site_id); @@ -54,14 +54,20 @@ export class EnterpriseService { }); } - insertMatomo(siteId = 5) { + insertMatomo(siteId?: number): void { let statsUrl = '//stats.mempool.space/'; - if (this.document.location.hostname === 'liquid.network') { - statsUrl = '//stats.liquid.network/'; - siteId = 8; - } else if (this.document.location.hostname === 'bisq.markets') { - statsUrl = '//stats.bisq.markets/'; - siteId = 7; + + if (!siteId) { + siteId = 5; + if (this.document.location.hostname === 'liquid.network') { + statsUrl = '//stats.liquid.network/'; + siteId = 8; + } else if (this.document.location.hostname === 'bisq.markets') { + statsUrl = '//stats.bisq.markets/'; + siteId = 7; + } else if (this.document.location.hostname !== 'mempool.space') { + return; + } } // @ts-ignore From 06453edc7cf65e51fc55829eb444d903a07d3cba Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 12 Aug 2022 12:12:34 +0200 Subject: [PATCH 11/14] Fix LN stats node per network count --- .../lightning/sync-tasks/stats-importer.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts index 8c823e2ef..7b618e66e 100644 --- a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts +++ b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts @@ -4,6 +4,8 @@ import { XMLParser } from 'fast-xml-parser'; import logger from '../../../logger'; import fundingTxFetcher from './funding-tx-fetcher'; import config from '../../../config'; +import { ILightningApi } from '../../../api/lightning/lightning-api.interface'; +import { isIP } from 'net'; const fsPromises = promises; @@ -48,7 +50,7 @@ class LightningStatsImporter { /** * Generate LN network stats for one day */ - public async computeNetworkStats(timestamp: number, networkGraph): Promise { + public async computeNetworkStats(timestamp: number, networkGraph: ILightningApi.NetworkGraph): Promise { // Node counts and network shares let clearnetNodes = 0; let torNodes = 0; @@ -61,8 +63,8 @@ class LightningStatsImporter { let isUnnanounced = true; for (const socket of (node.addresses ?? [])) { - hasOnion = hasOnion || ['torv2', 'torv3'].includes(socket.network); - hasClearnet = hasClearnet || ['ipv4', 'ipv6'].includes(socket.network); + hasOnion = hasOnion || ['torv2', 'torv3'].includes(socket.network) || socket.addr.indexOf('onion') !== -1; + hasClearnet = hasClearnet || ['ipv4', 'ipv6'].includes(socket.network) || [4, 6].includes(isIP(socket.addr.split(':')[0])); } if (hasOnion && hasClearnet) { clearnetTorNodes++; @@ -127,22 +129,28 @@ class LightningStatsImporter { if (channel.node1_policy !== undefined) { // Coming from the node for (const policy of [channel.node1_policy, channel.node2_policy]) { - if (policy && policy.fee_rate_milli_msat < 5000) { + if (policy && parseInt(policy.fee_rate_milli_msat, 10) < 5000) { avgFeeRate += parseInt(policy.fee_rate_milli_msat, 10); feeRates.push(parseInt(policy.fee_rate_milli_msat, 10)); } - if (policy && policy.fee_base_msat < 5000) { + if (policy && parseInt(policy.fee_base_msat, 10) < 5000) { avgBaseFee += parseInt(policy.fee_base_msat, 10); baseFees.push(parseInt(policy.fee_base_msat, 10)); } } } else { // Coming from the historical import + // @ts-ignore if (channel.fee_rate_milli_msat < 5000) { + // @ts-ignore avgFeeRate += parseInt(channel.fee_rate_milli_msat, 10); + // @ts-ignore feeRates.push(parseInt(channel.fee_rate_milli_msat), 10); - } + } + // @ts-ignore if (channel.fee_base_msat < 5000) { + // @ts-ignore avgBaseFee += parseInt(channel.fee_base_msat, 10); + // @ts-ignore baseFees.push(parseInt(channel.fee_base_msat), 10); } } From 576400414f3320deb49db13bb053d90d597fef06 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 12 Aug 2022 16:08:34 +0400 Subject: [PATCH 12/14] Adding staging matomo sites --- .../bisq-master-page.component.ts | 2 ++ .../liquid-master-page.component.ts | 2 ++ .../src/app/services/enterprise.service.ts | 36 ++++++++++++++----- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/components/bisq-master-page/bisq-master-page.component.ts b/frontend/src/app/components/bisq-master-page/bisq-master-page.component.ts index 0f10a106d..52da15125 100644 --- a/frontend/src/app/components/bisq-master-page/bisq-master-page.component.ts +++ b/frontend/src/app/components/bisq-master-page/bisq-master-page.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Env, StateService } from '../../services/state.service'; import { Observable } from 'rxjs'; import { LanguageService } from 'src/app/services/language.service'; +import { EnterpriseService } from 'src/app/services/enterprise.service'; @Component({ selector: 'app-bisq-master-page', @@ -18,6 +19,7 @@ export class BisqMasterPageComponent implements OnInit { constructor( private stateService: StateService, private languageService: LanguageService, + private enterpriseService: EnterpriseService, ) { } ngOnInit() { diff --git a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.ts b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.ts index 65f07320d..22a351068 100644 --- a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.ts +++ b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Env, StateService } from '../../services/state.service'; import { merge, Observable, of} from 'rxjs'; import { LanguageService } from 'src/app/services/language.service'; +import { EnterpriseService } from 'src/app/services/enterprise.service'; @Component({ selector: 'app-liquid-master-page', @@ -20,6 +21,7 @@ export class LiquidMasterPageComponent implements OnInit { constructor( private stateService: StateService, private languageService: LanguageService, + private enterpriseService: EnterpriseService, ) { } ngOnInit() { diff --git a/frontend/src/app/services/enterprise.service.ts b/frontend/src/app/services/enterprise.service.ts index 8f86d28a5..bc80f337d 100644 --- a/frontend/src/app/services/enterprise.service.ts +++ b/frontend/src/app/services/enterprise.service.ts @@ -58,15 +58,33 @@ export class EnterpriseService { let statsUrl = '//stats.mempool.space/'; if (!siteId) { - siteId = 5; - if (this.document.location.hostname === 'liquid.network') { - statsUrl = '//stats.liquid.network/'; - siteId = 8; - } else if (this.document.location.hostname === 'bisq.markets') { - statsUrl = '//stats.bisq.markets/'; - siteId = 7; - } else if (this.document.location.hostname !== 'mempool.space') { - return; + switch (this.document.location.hostname) { + case 'mempool.space': + statsUrl = '//stats.mempool.space/'; + siteId = 5; + break; + case 'mempool.ninja': + statsUrl = '//stats.mempool.space/'; + siteId = 4; + break; + case 'liquid.network': + siteId = 8; + statsUrl = '//stats.liquid.network/'; + break; + case 'liquid.place': + siteId = 10; + statsUrl = '//stats.liquid.network/'; + break; + case 'bisq.markets': + siteId = 7; + statsUrl = '//stats.bisq.markets/'; + break; + case 'bisq.ninja': + statsUrl = '//stats.bisq.markets/'; + siteId = 11; + break; + default: + return; } } From 39549c8ca98c247bd6c9d9453e8be49f653ada3b Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 12 Aug 2022 15:35:00 +0200 Subject: [PATCH 13/14] Show two LN network stats charts on dashboard --- .../lightning-dashboard.component.html | 15 +-- .../nodes-networks-chart.component.scss | 3 +- .../nodes-networks-chart.component.ts | 111 +++++++++++++----- .../nodes-per-isp-chart.component.html | 12 +- .../lightning-statistics-chart.component.scss | 2 +- .../lightning-statistics-chart.component.ts | 92 ++++++++++++--- .../app/shared/pipes/amount-shortener.pipe.ts | 2 +- 7 files changed, 169 insertions(+), 68 deletions(-) diff --git a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html index 3fbbaa4e2..e89ebaebf 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html @@ -37,24 +37,17 @@ - -
-
+
+
Lightning network history
+
diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.scss b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.scss index fa044a4d6..760e782ca 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.scss +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.scss @@ -51,8 +51,7 @@ } .chart-widget { width: 100%; - height: 100%; - max-height: 270px; + height: 145px; } .formRadioGroup { diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts index 70d02de28..4016cfc60 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core'; -import { EChartsOption} from 'echarts'; +import { EChartsOption, graphic} from 'echarts'; import { Observable } from 'rxjs'; import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; import { formatNumber } from '@angular/common'; @@ -9,6 +9,7 @@ import { MiningService } from 'src/app/services/mining.service'; import { download } from 'src/app/shared/graphs.utils'; import { SeoService } from 'src/app/services/seo.service'; import { LightningApiService } from '../lightning-api.service'; +import { AmountShortenerPipe } from 'src/app/shared/pipes/amount-shortener.pipe'; @Component({ selector: 'app-nodes-networks-chart', @@ -26,7 +27,7 @@ import { LightningApiService } from '../lightning-api.service'; }) export class NodesNetworksChartComponent implements OnInit { @Input() right: number | string = 45; - @Input() left: number | string = 55; + @Input() left: number | string = 45; @Input() widget = false; miningWindowPreference: string; @@ -51,7 +52,8 @@ export class NodesNetworksChartComponent implements OnInit { private lightningApiService: LightningApiService, private formBuilder: FormBuilder, private storageService: StorageService, - private miningService: MiningService + private miningService: MiningService, + private amountShortenerPipe: AmountShortenerPipe, ) { } @@ -82,11 +84,17 @@ export class NodesNetworksChartComponent implements OnInit { .pipe( tap((response) => { const data = response.body; - this.prepareChartOptions({ + const chartData = { tor_nodes: data.map(val => [val.added * 1000, val.tor_nodes]), clearnet_nodes: data.map(val => [val.added * 1000, val.clearnet_nodes]), unannounced_nodes: data.map(val => [val.added * 1000, val.unannounced_nodes]), - }); + }; + let maxYAxis = 0; + for (const day of data) { + maxYAxis = Math.max(maxYAxis, day.tor_nodes + day.clearnet_nodes + day.unannounced_nodes); + } + maxYAxis = Math.ceil(maxYAxis / 4000) * 4000; + this.prepareChartOptions(chartData, maxYAxis); this.isLoading = false; }), map((response) => { @@ -100,7 +108,7 @@ export class NodesNetworksChartComponent implements OnInit { ); } - prepareChartOptions(data) { + prepareChartOptions(data, maxYAxis) { let title: object; if (data.tor_nodes.length === 0) { title = { @@ -110,24 +118,30 @@ export class NodesNetworksChartComponent implements OnInit { }, text: $localize`:@@23555386d8af1ff73f297e89dd4af3f4689fb9dd:Indexing blocks`, left: 'center', - top: 'center' + top: 'top', + }; + } else if (this.widget) { + title = { + textStyle: { + color: 'grey', + fontSize: 11 + }, + text: $localize`Nodes per network`, + left: 'center', + top: 13, + zlevel: 10, }; } this.chartOptions = { title: title, animation: false, - color: [ - '#D81B60', - '#039BE5', - '#7CB342', - '#FFB300', - ], grid: { - top: 40, - bottom: this.widget ? 30 : 70, - right: this.right, - left: this.left, + height: this.widget ? 100 : undefined, + top: this.widget ? 10 : 40, + bottom: this.widget ? 0 : 70, + right: (this.isMobile() && this.widget) ? 35 : this.right, + left: (this.isMobile() && this.widget) ? 40 :this.left, }, tooltip: { show: !this.isMobile() || !this.widget, @@ -171,7 +185,7 @@ export class NodesNetworksChartComponent implements OnInit { hideOverlap: true, } }, - legend: data.tor_nodes.length === 0 ? undefined : { + legend: this.widget || data.tor_nodes.length === 0 ? undefined : { padding: 10, data: [ { @@ -207,7 +221,7 @@ export class NodesNetworksChartComponent implements OnInit { icon: 'roundRect', }, ], - selected: JSON.parse(this.storageService.getValue('nodes_networks_legend')) ?? { + selected: this.widget ? undefined : JSON.parse(this.storageService.getValue('nodes_networks_legend')) ?? { 'Total': true, 'Tor': true, 'Clearnet': true, @@ -218,13 +232,14 @@ export class NodesNetworksChartComponent implements OnInit { { type: 'value', position: 'left', - min: (value) => { - return value.min * 0.9; - }, axisLabel: { color: 'rgb(110, 112, 121)', - formatter: (val) => { - return `${formatNumber(Math.round(val * 100) / 100, this.locale, '1.0-0')}`; + formatter: (val: number): string => { + if (this.widget) { + return `${this.amountShortenerPipe.transform(val, 0)}`; + } else { + return `${formatNumber(Math.round(val), this.locale, '1.0-0')}`; + } } }, splitLine: { @@ -232,8 +247,35 @@ export class NodesNetworksChartComponent implements OnInit { type: 'dotted', color: '#ffffff66', opacity: 0.25, + }, + }, + max: maxYAxis, + min: 0, + interval: 4000, + }, + { + type: 'value', + position: 'right', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val: number): string => { + if (this.widget) { + return `${this.amountShortenerPipe.transform(val, 0)}`; + } else { + return `${formatNumber(Math.round(val), this.locale, '1.0-0')}`; + } } }, + splitLine: { + lineStyle: { + type: 'dotted', + color: '#ffffff66', + opacity: 0.25, + }, + }, + max: maxYAxis, + min: 0, + interval: 4000, } ], series: data.tor_nodes.length === 0 ? [] : [ @@ -252,7 +294,12 @@ export class NodesNetworksChartComponent implements OnInit { opacity: 0.5, }, stack: 'Total', - color: '#FDD835', + color: new graphic.LinearGradient(0, 0.75, 0, 1, [ + { offset: 0, color: '#D81B60' }, + { offset: 1, color: '#D81B60AA' }, + ]), + + smooth: true, }, { zlevel: 1, @@ -269,11 +316,15 @@ export class NodesNetworksChartComponent implements OnInit { opacity: 0.5, }, stack: 'Total', - color: '#00ACC1', + color: new graphic.LinearGradient(0, 0.75, 0, 1, [ + { offset: 0, color: '#FFB300' }, + { offset: 1, color: '#FFB300AA' }, + ]), + smooth: true, }, { zlevel: 1, - yAxisIndex: 0, + yAxisIndex: 1, name: $localize`Tor`, showSymbol: false, symbol: 'none', @@ -286,7 +337,11 @@ export class NodesNetworksChartComponent implements OnInit { opacity: 0.5, }, stack: 'Total', - color: '#7D4698', + color: new graphic.LinearGradient(0, 0.75, 0, 1, [ + { offset: 0, color: '#7D4698' }, + { offset: 1, color: '#7D4698AA' }, + ]), + smooth: true, }, ], dataZoom: this.widget ? null : [{ diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html index 5e14ac67b..01be4f036 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.html @@ -8,18 +8,18 @@ {{ stats.taggedISP }}

-
-
Tagged capacity
-

- -

-
Tagged nodes

{{ stats.taggedNodeCount }}

+
+
Tagged capacity
+

+ +

+
diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss index 5f59539e3..760e782ca 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.scss @@ -51,7 +51,7 @@ } .chart-widget { width: 100%; - height: 320px; + height: 145px; } .formRadioGroup { diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts index 1727d1f68..ea997f8db 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts @@ -9,6 +9,7 @@ import { StorageService } from 'src/app/services/storage.service'; import { MiningService } from 'src/app/services/mining.service'; import { download } from 'src/app/shared/graphs.utils'; import { LightningApiService } from '../lightning-api.service'; +import { AmountShortenerPipe } from 'src/app/shared/pipes/amount-shortener.pipe'; @Component({ selector: 'app-lightning-statistics-chart', @@ -25,7 +26,7 @@ import { LightningApiService } from '../lightning-api.service'; }) export class LightningStatisticsChartComponent implements OnInit { @Input() right: number | string = 45; - @Input() left: number | string = 55; + @Input() left: number | string = 45; @Input() widget = false; miningWindowPreference: string; @@ -51,6 +52,7 @@ export class LightningStatisticsChartComponent implements OnInit { private formBuilder: FormBuilder, private storageService: StorageService, private miningService: MiningService, + private amountShortenerPipe: AmountShortenerPipe, ) { } @@ -105,24 +107,39 @@ export class LightningStatisticsChartComponent implements OnInit { color: 'grey', fontSize: 15 }, - text: `Indexing in progess`, + text: $localize`Indexing in progess`, left: 'center', top: 'center' }; + } else if (this.widget) { + title = { + textStyle: { + color: 'grey', + fontSize: 11 + }, + text: $localize`Channels & Capacity`, + left: 'center', + top: 13, + zlevel: 10, + }; } this.chartOptions = { title: title, animation: false, color: [ - '#FDD835', - '#D81B60', + '#FFB300', + new graphic.LinearGradient(0, 0.75, 0, 1, [ + { offset: 0, color: '#D81B60' }, + { offset: 1, color: '#D81B60AA' }, + ]), ], grid: { - top: 40, - bottom: this.widget ? 30 : 70, - right: this.right, - left: this.left, + height: this.widget ? 100 : undefined, + top: this.widget ? 10 : 40, + bottom: this.widget ? 0 : 70, + right: (this.isMobile() && this.widget) ? 35 : this.right, + left: (this.isMobile() && this.widget) ? 40 :this.left, }, tooltip: { show: !this.isMobile(), @@ -166,7 +183,7 @@ export class LightningStatisticsChartComponent implements OnInit { hideOverlap: true, } }, - legend: data.channel_count.length === 0 ? undefined : { + legend: this.widget || data.channel_count.length === 0 ? undefined : { padding: 10, data: [ { @@ -178,7 +195,7 @@ export class LightningStatisticsChartComponent implements OnInit { icon: 'roundRect', }, { - name: 'Capacity (BTC)', + name: 'Capacity', inactiveColor: 'rgb(110, 112, 121)', textStyle: { color: 'white', @@ -188,17 +205,20 @@ export class LightningStatisticsChartComponent implements OnInit { ], selected: JSON.parse(this.storageService.getValue('sizes_ln_legend')) ?? { 'Channels': true, - 'Capacity (BTC)': true, + 'Capacity': true, } }, yAxis: data.channel_count.length === 0 ? undefined : [ { - min: 0, type: 'value', axisLabel: { color: 'rgb(110, 112, 121)', - formatter: (val) => { - return `${formatNumber(Math.round(val), this.locale, '1.0-0')}`; + formatter: (val: number): string => { + if (this.widget) { + return `${this.amountShortenerPipe.transform(val, 0)}`; + } else { + return `${formatNumber(Math.round(val), this.locale, '1.0-0')}`; + } } }, splitLine: { @@ -208,6 +228,7 @@ export class LightningStatisticsChartComponent implements OnInit { opacity: 0.25, } }, + minInterval: this.widget ? 20000 : undefined, }, { min: 0, @@ -215,8 +236,12 @@ export class LightningStatisticsChartComponent implements OnInit { position: 'right', axisLabel: { color: 'rgb(110, 112, 121)', - formatter: (val) => { - return `${formatNumber(Math.round(val / 100000000), this.locale, '1.0-0')}`; + formatter: (val: number): string => { + if (this.widget) { + return `${this.amountShortenerPipe.transform(Math.round(val / 100000000), 0)}`; + } else { + return `${formatNumber(Math.round(val / 100000000), this.locale, '1.0-0')}`; + } } }, splitLine: { @@ -244,20 +269,49 @@ export class LightningStatisticsChartComponent implements OnInit { opacity: 1, width: 1, }, - } + }, + smooth: true, }, { zlevel: 0, yAxisIndex: 1, - name: 'Capacity (BTC)', + name: $localize`Capacity`, showSymbol: false, symbol: 'none', stack: 'Total', data: data.capacity, - areaStyle: {}, + areaStyle: { + opacity: 0.5, + }, type: 'line', + smooth: true, } ], + dataZoom: this.widget ? null : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], }; } diff --git a/frontend/src/app/shared/pipes/amount-shortener.pipe.ts b/frontend/src/app/shared/pipes/amount-shortener.pipe.ts index a31a5712e..db3d94284 100644 --- a/frontend/src/app/shared/pipes/amount-shortener.pipe.ts +++ b/frontend/src/app/shared/pipes/amount-shortener.pipe.ts @@ -5,7 +5,7 @@ import { Pipe, PipeTransform } from '@angular/core'; }) export class AmountShortenerPipe implements PipeTransform { transform(num: number, ...args: any[]): unknown { - const digits = args[0] || 1; + const digits = args[0] ?? 1; const unit = args[1] || undefined; if (num < 1000) { From 0c13d9f5856d76df3f4dd4c93719f84b257b3f56 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Fri, 12 Aug 2022 15:40:19 +0200 Subject: [PATCH 14/14] Update yaxis scale and view more link --- .../lightning-dashboard.component.html | 2 +- .../nodes-networks-chart.component.ts | 8 ++++---- .../lightning-statistics-chart.component.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html index e89ebaebf..ff00f5b15 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html @@ -48,7 +48,7 @@
Lightning network history
- + diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts index 4016cfc60..dbbb49483 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts @@ -93,7 +93,7 @@ export class NodesNetworksChartComponent implements OnInit { for (const day of data) { maxYAxis = Math.max(maxYAxis, day.tor_nodes + day.clearnet_nodes + day.unannounced_nodes); } - maxYAxis = Math.ceil(maxYAxis / 4000) * 4000; + maxYAxis = Math.ceil(maxYAxis / 3000) * 3000; this.prepareChartOptions(chartData, maxYAxis); this.isLoading = false; }), @@ -128,7 +128,7 @@ export class NodesNetworksChartComponent implements OnInit { }, text: $localize`Nodes per network`, left: 'center', - top: 13, + top: 11, zlevel: 10, }; } @@ -251,7 +251,7 @@ export class NodesNetworksChartComponent implements OnInit { }, max: maxYAxis, min: 0, - interval: 4000, + interval: 3000, }, { type: 'value', @@ -275,7 +275,7 @@ export class NodesNetworksChartComponent implements OnInit { }, max: maxYAxis, min: 0, - interval: 4000, + interval: 3000, } ], series: data.tor_nodes.length === 0 ? [] : [ diff --git a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts index ea997f8db..d889dd254 100644 --- a/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts +++ b/frontend/src/app/lightning/statistics-chart/lightning-statistics-chart.component.ts @@ -119,7 +119,7 @@ export class LightningStatisticsChartComponent implements OnInit { }, text: $localize`Channels & Capacity`, left: 'center', - top: 13, + top: 11, zlevel: 10, }; }