Merge branch 'master' into nymkappa/bugfix/channel-map-rendering
This commit is contained in:
		
						commit
						0f4b127275
					
				@ -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)`;
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
@ -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');
 | 
			
		||||
 | 
			
		||||
@ -76,10 +76,8 @@
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div [class]="!widget ? 'bottom-padding' : 'pb-0'" class="container pb-lg-0">
 | 
			
		||||
    <div>
 | 
			
		||||
      <div [class]="widget ? 'chart-widget' : 'chart'" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
 | 
			
		||||
        (chartInit)="onChartInit($event)">
 | 
			
		||||
      </div>
 | 
			
		||||
    <div [class]="widget ? 'chart-widget' : 'chart'" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
 | 
			
		||||
      (chartInit)="onChartInit($event)">
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="text-center loadingGraphs" *ngIf="isLoading">
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
  <div class="row row-cols-1 row-cols-md-2">
 | 
			
		||||
 | 
			
		||||
    <!-- Network capacity/channels/nodes -->
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="main-title">
 | 
			
		||||
        <span i18n="lightning.statistics-title">Network Statistics</span> 
 | 
			
		||||
@ -17,6 +18,7 @@
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- Channels stats -->
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="main-title">
 | 
			
		||||
        <span i18n="lightning.statistics-title">Channels Statistics</span> 
 | 
			
		||||
@ -30,18 +32,28 @@
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="col">
 | 
			
		||||
    <!-- ISP pie chart -->
 | 
			
		||||
    <div class="col" style="margin-bottom: 1.47rem">
 | 
			
		||||
      <div class="card graph-card">
 | 
			
		||||
        <div class="card-body pl-2 pr-2">
 | 
			
		||||
          <app-nodes-per-isp-chart [widget]="true"></app-nodes-per-isp-chart>
 | 
			
		||||
          <div class="mt-1"><a [attr.data-cy]="'pool-distribution-view-more'" [routerLink]="['/graphs/lightning/nodes-per-isp' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- <div class="col">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <app-nodes-networks-chart [widget]=true></app-nodes-networks-chart>
 | 
			
		||||
          <div class="mt-1"><a [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div> -->
 | 
			
		||||
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
      <div class="card graph-card">
 | 
			
		||||
        <div class="card-body pl-2 pr-2">
 | 
			
		||||
          <app-lightning-statistics-chart [widget]=true></app-lightning-statistics-chart>
 | 
			
		||||
          <div class="mt-1"><a [routerLink]="['/graphs/lightning/capacity' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div>
 | 
			
		||||
        </div>
 | 
			
		||||
@ -52,7 +64,7 @@
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <h5 class="card-title">Top Capacity Nodes</h5>
 | 
			
		||||
          <app-nodes-list [nodes$]="nodesByCapacity$"></app-nodes-list>
 | 
			
		||||
          <app-nodes-list [nodes$]="nodesByCapacity$" [show]="'mobile-capacity'"></app-nodes-list>
 | 
			
		||||
          <!-- <div><a [routerLink]="['/lightning/nodes' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div> -->
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
@ -62,7 +74,7 @@
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <h5 class="card-title">Most Connected Nodes</h5>
 | 
			
		||||
          <app-nodes-list [nodes$]="nodesByChannels$"></app-nodes-list>
 | 
			
		||||
          <app-nodes-list [nodes$]="nodesByChannels$" [show]="'mobile-channels'"></app-nodes-list>
 | 
			
		||||
          <!-- <div><a [routerLink]="['/lightning/nodes' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div> -->
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -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`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -3,18 +3,18 @@
 | 
			
		||||
  <table class="table table-borderless">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <th class="alias text-left" i18n="nodes.alias">Alias</th>
 | 
			
		||||
      <th class="capacity text-right" i18n="node.capacity">Capacity</th>
 | 
			
		||||
      <th class="channels text-right" i18n="node.channels">Channels</th>
 | 
			
		||||
      <th class="capacity text-right" [class]="show" i18n="node.capacity">Capacity</th>
 | 
			
		||||
      <th class="channels text-right" [class]="show" i18n="node.channels">Channels</th>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody *ngIf="nodes$ | async as nodes; else skeleton">
 | 
			
		||||
      <tr *ngFor="let node of nodes; let i = index;">
 | 
			
		||||
        <td class="alias text-left">
 | 
			
		||||
          <a [routerLink]="['/lightning/node' | relativeUrl, node.public_key]">{{ node.alias }}</a>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td class="capacity text-right">
 | 
			
		||||
        <td class="capacity text-right" [class]="show">
 | 
			
		||||
          <app-amount [satoshis]="node.capacity" digitsInfo="1.2-2"></app-amount>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td class="channels text-right">
 | 
			
		||||
        <td class="channels text-right" [class]="show">
 | 
			
		||||
          {{ node.channels | number }}
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
.capacity.mobile-channels {
 | 
			
		||||
  @media (max-width: 767.98px) {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.channels.mobile-capacity {
 | 
			
		||||
  @media (max-width: 767.98px) {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -9,6 +9,7 @@ import { Observable } from 'rxjs';
 | 
			
		||||
})
 | 
			
		||||
export class NodesListComponent implements OnInit {
 | 
			
		||||
  @Input() nodes$: Observable<any>;
 | 
			
		||||
  @Input() show: string;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,29 @@
 | 
			
		||||
<div class="full-container h-100">
 | 
			
		||||
<div [class]="widget === false ? 'full-container' : ''">
 | 
			
		||||
 | 
			
		||||
  <div class="card-header">
 | 
			
		||||
  <div *ngIf="widget">
 | 
			
		||||
    <div class="pool-distribution" *ngIf="(nodesPerAsObservable$ | async) as stats; else loadingReward">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <h5 class="card-title d-inline-block" i18n="lightning.tagged-isp">Tagged ISPs</h5>
 | 
			
		||||
        <p class="card-text">
 | 
			
		||||
          {{ stats.taggedISP }}
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <h5 class="card-title d-inline-block" i18n="lightning.tagged-capacity">Tagged capacity</h5>
 | 
			
		||||
        <p class="card-text" i18n-ngbTooltip="mining.blocks-count-desc">
 | 
			
		||||
          <app-amount [satoshis]="stats.taggedCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <h5 class="card-title d-inline-block" i18n="lightning.tagged-nodes">Tagged nodes</h5>
 | 
			
		||||
        <p class="card-text" i18n-ngbTooltip="mining.pools-count-desc">
 | 
			
		||||
          {{ stats.taggedNodeCount }}
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="card-header" *ngIf="!widget">
 | 
			
		||||
    <div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
 | 
			
		||||
      <span i18n="lightning.nodes-per-isp">Lightning nodes per ISP</span>
 | 
			
		||||
      <button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
 | 
			
		||||
@ -12,23 +35,21 @@
 | 
			
		||||
    </small>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="container pb-lg-0 bottom-padding">
 | 
			
		||||
    <div class="pb-lg-5" *ngIf="nodesPerAsObservable$ | async">
 | 
			
		||||
      <div class="chart w-100" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
 | 
			
		||||
        (chartInit)="onChartInit($event)">
 | 
			
		||||
      </div>
 | 
			
		||||
  <div [class]="!widget ? 'bottom-padding' : 'pb-0'" class="container pb-lg-0">
 | 
			
		||||
    <div [class]="widget ? 'chart-widget' : 'chart'" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
 | 
			
		||||
      (chartInit)="onChartInit($event)">
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="text-center loadingGraphs" *ngIf="isLoading">
 | 
			
		||||
      <div class="spinner-border text-light"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="d-flex toggle">
 | 
			
		||||
    <div class="d-flex toggle" *ngIf="!widget">
 | 
			
		||||
      <app-toggle [textLeft]="'Show Tor'" [textRight]="" (toggleStatusChanged)="onTorToggleStatusChanged($event)"></app-toggle>
 | 
			
		||||
      <app-toggle [textLeft]="'Nodes'" [textRight]="'Capacity'" (toggleStatusChanged)="onGroupToggleStatusChanged($event)"></app-toggle>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <table class="table table-borderless text-center m-auto" style="max-width: 900px">
 | 
			
		||||
    <table class="table table-borderless text-center m-auto" style="max-width: 900px"  *ngIf="!widget">
 | 
			
		||||
      <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <th class="rank text-left pl-0" i18n="mining.rank">Rank</th>
 | 
			
		||||
@ -39,7 +60,7 @@
 | 
			
		||||
        </tr>
 | 
			
		||||
      </thead>
 | 
			
		||||
      <tbody [attr.data-cy]="'pools-table'" *ngIf="(nodesPerAsObservable$ | async) as asList">
 | 
			
		||||
        <tr *ngFor="let asEntry of asList">
 | 
			
		||||
        <tr *ngFor="let asEntry of asList.data">
 | 
			
		||||
          <td class="rank text-left pl-0">{{ asEntry.rank }}</td>
 | 
			
		||||
          <td class="name text-left text-truncate">
 | 
			
		||||
            <a *ngIf="asEntry.ispId" [routerLink]="[('/lightning/nodes/isp/' + asEntry.ispId) | relativeUrl]">{{ asEntry.name }}</a>
 | 
			
		||||
@ -54,3 +75,26 @@
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<ng-template #loadingReward>
 | 
			
		||||
  <div class="pool-distribution">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="lightning.tagged-isp">Tagged ISPs</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="lightning.tagged-capacity">Tagged capacity</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="lightning.tagged-nodes">Tagged nodes</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -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) {
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -51,8 +51,7 @@
 | 
			
		||||
}
 | 
			
		||||
.chart-widget {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  max-height: 270px;
 | 
			
		||||
  height: 320px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.formRadioGroup {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user