Add Lightning charts in /graph
This commit is contained in:
parent
37f731d21c
commit
ed3aa7f516
@ -10,7 +10,7 @@ class GeneralLightningRoutes {
|
|||||||
app
|
app
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/search', this.$searchNodesAndChannels)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/search', this.$searchNodesAndChannels)
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/statistics/latest', this.$getGeneralStats)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/statistics/latest', this.$getGeneralStats)
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/statistics', this.$getStatistics)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/statistics/:interval', this.$getStatistics)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,12 @@ class GeneralLightningRoutes {
|
|||||||
|
|
||||||
private async $getStatistics(req: Request, res: Response) {
|
private async $getStatistics(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const statistics = await statisticsApi.$getStatistics();
|
const statistics = await statisticsApi.$getStatistics(req.params.interval);
|
||||||
|
const statisticsCount = await statisticsApi.$getStatisticsCount();
|
||||||
|
res.header('Pragma', 'public');
|
||||||
|
res.header('Cache-control', 'public');
|
||||||
|
res.header('X-total-count', statisticsCount.toString());
|
||||||
|
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||||
res.json(statistics);
|
res.json(statistics);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).send(e instanceof Error ? e.message : e);
|
res.status(500).send(e instanceof Error ? e.message : e);
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
import logger from '../../logger';
|
import logger from '../../logger';
|
||||||
import DB from '../../database';
|
import DB from '../../database';
|
||||||
|
import { Common } from '../common';
|
||||||
|
|
||||||
class StatisticsApi {
|
class StatisticsApi {
|
||||||
public async $getStatistics(): Promise<any> {
|
public async $getStatistics(interval: string | null = null): Promise<any> {
|
||||||
|
interval = Common.getSqlInterval(interval);
|
||||||
|
|
||||||
|
let query = `SELECT UNIX_TIMESTAMP(added) AS added, channel_count, node_count, total_capacity, tor_nodes, clearnet_nodes, unannounced_nodes
|
||||||
|
FROM lightning_stats`;
|
||||||
|
|
||||||
|
if (interval) {
|
||||||
|
query += ` WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ` ORDER BY id DESC`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const query = `SELECT UNIX_TIMESTAMP(added) AS added, channel_count, node_count, total_capacity, tor_nodes, clearnet_nodes, unannounced_nodes FROM lightning_stats ORDER BY id DESC`;
|
|
||||||
const [rows]: any = await DB.query(query);
|
const [rows]: any = await DB.query(query);
|
||||||
return rows;
|
return rows;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -27,6 +38,15 @@ class StatisticsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $getStatisticsCount(): Promise<number> {
|
||||||
|
try {
|
||||||
|
const [rows]: any = await DB.query(`SELECT count(*) as count FROM lightning_stats`);
|
||||||
|
return rows[0].count;
|
||||||
|
} catch (e) {
|
||||||
|
logger.err('$getLatestStatistics error: ' + (e instanceof Error ? e.message : e));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new StatisticsApi();
|
export default new StatisticsApi();
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<div *ngIf="stateService.env.MINING_DASHBOARD" class="mb-3 d-inline-flex menu" style="padding: 0px 35px;">
|
<div *ngIf="stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING" class="mb-3 d-flex menu"
|
||||||
|
style="padding: 0px 35px;">
|
||||||
|
|
||||||
<a routerLinkActive="active" class="btn btn-primary w-50 mr-1"
|
<a routerLinkActive="active" class="btn btn-primary w-50 mr-1"
|
||||||
[routerLink]="['/graphs/mempool' | relativeUrl]">Mempool</a>
|
[routerLink]="['/graphs/mempool' | relativeUrl]">Mempool</a>
|
||||||
<div ngbDropdown class="w-50">
|
|
||||||
|
<div ngbDropdown class="w-50" *ngIf="stateService.env.MINING_DASHBOARD">
|
||||||
<button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="mining">Mining</button>
|
<button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="mining">Mining</button>
|
||||||
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools' | relativeUrl]"
|
||||||
@ -9,19 +12,30 @@
|
|||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools-dominance' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools-dominance' | relativeUrl]"
|
||||||
i18n="mining.pools-dominance">Pools Dominance</a>
|
i18n="mining.pools-dominance">Pools Dominance</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active"
|
<a class="dropdown-item" routerLinkActive="active"
|
||||||
[routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" i18n="mining.hashrate-difficulty">Hashrate & Difficulty</a>
|
[routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" i18n="mining.hashrate-difficulty">Hashrate &
|
||||||
<a class="dropdown-item" routerLinkActive="active"
|
Difficulty</a>
|
||||||
[routerLink]="['/graphs/mining/block-fee-rates' | relativeUrl]" i18n="mining.block-fee-rates">Block Fee Rates</a>
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/block-fee-rates' | relativeUrl]"
|
||||||
<a class="dropdown-item" routerLinkActive="active"
|
i18n="mining.block-fee-rates">Block Fee Rates</a>
|
||||||
[routerLink]="['/graphs/mining/block-fees' | relativeUrl]" i18n="mining.block-fees">Block Fees</a>
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/block-fees' | relativeUrl]"
|
||||||
<a class="dropdown-item" routerLinkActive="active"
|
i18n="mining.block-fees">Block Fees</a>
|
||||||
[routerLink]="['/graphs/mining/block-rewards' | relativeUrl]" i18n="mining.block-rewards">Block Rewards</a>
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/block-rewards' | relativeUrl]"
|
||||||
|
i18n="mining.block-rewards">Block Rewards</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active"
|
<a class="dropdown-item" routerLinkActive="active"
|
||||||
[routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]" i18n="mining.block-sizes-weights">Block Sizes and Weights</a>
|
[routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]" i18n="mining.block-sizes-weights">Block Sizes and Weights</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active"
|
<a class="dropdown-item" routerLinkActive="active"
|
||||||
[routerLink]="['/graphs/mining/block-prediction' | relativeUrl]" i18n="mining.block-prediction-accuracy">Block Prediction Accuracy</a>
|
[routerLink]="['/graphs/mining/block-prediction' | relativeUrl]" i18n="mining.block-prediction-accuracy">Block Prediction Accuracy</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div ngbDropdown class="w-50" *ngIf="stateService.env.LIGHTNING">
|
||||||
|
<button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="lightning">Lightning</button>
|
||||||
|
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
||||||
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"
|
||||||
|
i18n="lightning.nodes-networks">Nodes per network</a>
|
||||||
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/capacity' | relativeUrl]"
|
||||||
|
i18n="lightning.capacity">Network capacity</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
@ -18,6 +18,8 @@ import { StartComponent } from '../components/start/start.component';
|
|||||||
import { StatisticsComponent } from '../components/statistics/statistics.component';
|
import { StatisticsComponent } from '../components/statistics/statistics.component';
|
||||||
import { TelevisionComponent } from '../components/television/television.component';
|
import { TelevisionComponent } from '../components/television/television.component';
|
||||||
import { DashboardComponent } from '../dashboard/dashboard.component';
|
import { DashboardComponent } from '../dashboard/dashboard.component';
|
||||||
|
import { NodesNetworksChartComponent } from '../lightning/nodes-networks-chart/nodes-networks-chart.component';
|
||||||
|
import { LightningStatisticsChartComponent } from '../lightning/statistics-chart/lightning-statistics-chart.component';
|
||||||
|
|
||||||
const browserWindow = window || {};
|
const browserWindow = window || {};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -89,6 +91,14 @@ const routes: Routes = [
|
|||||||
path: 'mining/block-sizes-weights',
|
path: 'mining/block-sizes-weights',
|
||||||
component: BlockSizesWeightsGraphComponent,
|
component: BlockSizesWeightsGraphComponent,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'lightning/nodes-networks',
|
||||||
|
component: NodesNetworksChartComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'lightning/capacity',
|
||||||
|
component: LightningStatisticsChartComponent,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: 'mempool',
|
redirectTo: 'mempool',
|
||||||
|
@ -56,7 +56,10 @@ export class LightningApiService {
|
|||||||
return this.httpClient.get<any>(this.apiBasePath + '/channels/' + publicKey + '/statistics');
|
return this.httpClient.get<any>(this.apiBasePath + '/channels/' + publicKey + '/statistics');
|
||||||
}
|
}
|
||||||
|
|
||||||
listStatistics$(): Observable<any> {
|
listStatistics$(interval: string | undefined): Observable<any> {
|
||||||
return this.httpClient.get<any>(this.apiBasePath + '/api/v1/lightning/statistics');
|
return this.httpClient.get<any>(
|
||||||
|
this.apiBasePath + '/api/v1/lightning/statistics' +
|
||||||
|
(interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<app-lightning-statistics-chart [widget]=true></app-lightning-statistics-chart>
|
<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>
|
</div>
|
||||||
@ -39,7 +40,8 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<app-nodes-networks-chart [widget]=true></app-nodes-networks-chart>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,35 +8,26 @@
|
|||||||
|
|
||||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(nodesNetworkObservable$ | async) as stats">
|
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(nodesNetworkObservable$ | async) as stats">
|
||||||
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
|
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 144">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 30">
|
||||||
<input ngbButton type="radio" [value]="'24h'" fragment="24h" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 24h
|
<input ngbButton type="radio" [value]="'1m'" fragment="1m" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> 1M
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 432">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 90">
|
||||||
<input ngbButton type="radio" [value]="'3d'" fragment="3d" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 3D
|
<input ngbButton type="radio" [value]="'3m'" fragment="3m" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> 3M
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 1008">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 180">
|
||||||
<input ngbButton type="radio" [value]="'1w'" fragment="1w" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 1W
|
<input ngbButton type="radio" [value]="'6m'" fragment="6m" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> 6M
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 4320">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 365">
|
||||||
<input ngbButton type="radio" [value]="'1m'" fragment="1m" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 1M
|
<input ngbButton type="radio" [value]="'1y'" fragment="1y" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> 1Y
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 12960">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 730">
|
||||||
<input ngbButton type="radio" [value]="'3m'" fragment="3m" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 3M
|
<input ngbButton type="radio" [value]="'2y'" fragment="2y" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> 2Y
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 25920">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 1095">
|
||||||
<input ngbButton type="radio" [value]="'6m'" fragment="6m" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 6M
|
<input ngbButton type="radio" [value]="'3y'" fragment="3y" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> 3Y
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 52560">
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
<input ngbButton type="radio" [value]="'1y'" fragment="1y" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 1Y
|
<input ngbButton type="radio" [value]="'all'" fragment="all" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"> ALL
|
||||||
</label>
|
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 105120">
|
|
||||||
<input ngbButton type="radio" [value]="'2y'" fragment="2y" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 2Y
|
|
||||||
</label>
|
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 157680">
|
|
||||||
<input ngbButton type="radio" [value]="'3y'" fragment="3y" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> 3Y
|
|
||||||
</label>
|
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount > 157680">
|
|
||||||
<input ngbButton type="radio" [value]="'all'" fragment="all" [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]"> ALL
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
|
||||||
import { EChartsOption} from 'echarts';
|
import { EChartsOption} from 'echarts';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { startWith, switchMap, tap } from 'rxjs/operators';
|
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
|
||||||
import { formatNumber } from '@angular/common';
|
import { formatNumber } from '@angular/common';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { StorageService } from 'src/app/services/storage.service';
|
import { StorageService } from 'src/app/services/storage.service';
|
||||||
import { MiningService } from 'src/app/services/mining.service';
|
import { MiningService } from 'src/app/services/mining.service';
|
||||||
import { download, formatterXAxis } from 'src/app/shared/graphs.utils';
|
import { download } from 'src/app/shared/graphs.utils';
|
||||||
import { SeoService } from 'src/app/services/seo.service';
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
import { LightningApiService } from '../lightning-api.service';
|
import { LightningApiService } from '../lightning-api.service';
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
this.miningWindowPreference = '1y';
|
this.miningWindowPreference = '1y';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`Nodes per network`);
|
this.seoService.setTitle($localize`Nodes per network`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('1m');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
@ -73,14 +73,15 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
switchMap((timespan) => {
|
switchMap((timespan) => {
|
||||||
this.timespan = timespan;
|
this.timespan = timespan;
|
||||||
if (!this.widget && !firstRun) {
|
if (!this.widget && !firstRun) {
|
||||||
this.storageService.setValue('miningWindowPreference', timespan);
|
this.storageService.setValue('lightningWindowPreference', timespan);
|
||||||
}
|
}
|
||||||
firstRun = false;
|
firstRun = false;
|
||||||
this.miningWindowPreference = timespan;
|
this.miningWindowPreference = timespan;
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
return this.lightningApiService.listStatistics$()
|
return this.lightningApiService.listStatistics$(timespan)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((data) => {
|
tap((response) => {
|
||||||
|
const data = response.body;
|
||||||
this.prepareChartOptions({
|
this.prepareChartOptions({
|
||||||
node_count: data.map(val => [val.added * 1000, val.node_count]),
|
node_count: data.map(val => [val.added * 1000, val.node_count]),
|
||||||
tor_nodes: data.map(val => [val.added * 1000, val.tor_nodes]),
|
tor_nodes: data.map(val => [val.added * 1000, val.tor_nodes]),
|
||||||
@ -89,9 +90,15 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}),
|
}),
|
||||||
|
map((response) => {
|
||||||
|
return {
|
||||||
|
days: parseInt(response.headers.get('x-total-count'), 10),
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
)
|
share()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareChartOptions(data) {
|
prepareChartOptions(data) {
|
||||||
|
@ -5,9 +5,43 @@
|
|||||||
<button class="btn" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
<button class="btn" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
||||||
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(capacityObservable$ | async) as stats">
|
||||||
|
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 30">
|
||||||
|
<input ngbButton type="radio" [value]="'1m'" fragment="1m"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> 1M
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 90">
|
||||||
|
<input ngbButton type="radio" [value]="'3m'" fragment="3m"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> 3M
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 180">
|
||||||
|
<input ngbButton type="radio" [value]="'6m'" fragment="6m"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> 6M
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 365">
|
||||||
|
<input ngbButton type="radio" [value]="'1y'" fragment="1y"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> 1Y
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 730">
|
||||||
|
<input ngbButton type="radio" [value]="'2y'" fragment="2y"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> 2Y
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.days >= 1095">
|
||||||
|
<input ngbButton type="radio" [value]="'3y'" fragment="3y"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> 3Y
|
||||||
|
</label>
|
||||||
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
|
<input ngbButton type="radio" [value]="'all'" fragment="all"
|
||||||
|
[routerLink]="['/graphs/lightning/capacity' | relativeUrl]"> ALL
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [class]="!widget ? 'chart' : 'chart-widget'" echarts [initOpts]="chartInitOptions" [options]="chartOptions" (chartInit)="onChartInit($event)"></div>
|
<div [class]="!widget ? 'chart' : 'chart-widget'" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
|
||||||
|
(chartInit)="onChartInit($event)"></div>
|
||||||
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
||||||
<div class="spinner-border text-light"></div>
|
<div class="spinner-border text-light"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
|
import { Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
|
||||||
import { EChartsOption, graphic } from 'echarts';
|
import { EChartsOption, graphic } from 'echarts';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { startWith, switchMap, tap } from 'rxjs/operators';
|
import { map, startWith, switchMap, tap } from 'rxjs/operators';
|
||||||
import { SeoService } from 'src/app/services/seo.service';
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
import { formatNumber } from '@angular/common';
|
import { formatNumber } from '@angular/common';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
@ -38,7 +38,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
|
|
||||||
@HostBinding('attr.dir') dir = 'ltr';
|
@HostBinding('attr.dir') dir = 'ltr';
|
||||||
|
|
||||||
blockSizesWeightsObservable$: Observable<any>;
|
capacityObservable$: Observable<any>;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
formatNumber = formatNumber;
|
formatNumber = formatNumber;
|
||||||
timespan = '';
|
timespan = '';
|
||||||
@ -57,34 +57,44 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
let firstRun = true;
|
let firstRun = true;
|
||||||
|
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
if (this.widget) {
|
||||||
|
this.miningWindowPreference = '1y';
|
||||||
|
} else {
|
||||||
|
this.seoService.setTitle($localize`Channels and Capacity`);
|
||||||
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
||||||
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
|
||||||
this.radioGroupForm.get('dateSpan').valueChanges
|
this.capacityObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
startWith(this.miningWindowPreference),
|
startWith(this.miningWindowPreference),
|
||||||
switchMap((timespan) => {
|
switchMap((timespan) => {
|
||||||
this.timespan = timespan;
|
this.timespan = timespan;
|
||||||
if (!firstRun) {
|
if (!this.widget && !firstRun) {
|
||||||
this.storageService.setValue('miningWindowPreference', timespan);
|
this.storageService.setValue('lightningWindowPreference', timespan);
|
||||||
}
|
}
|
||||||
firstRun = false;
|
firstRun = false;
|
||||||
this.miningWindowPreference = timespan;
|
this.miningWindowPreference = timespan;
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
return this.lightningApiService.listStatistics$()
|
return this.lightningApiService.listStatistics$(timespan)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((data) => {
|
tap((response) => {
|
||||||
|
const data = response.body;
|
||||||
this.prepareChartOptions({
|
this.prepareChartOptions({
|
||||||
channel_count: data.map(val => [val.added * 1000, val.channel_count]),
|
channel_count: data.map(val => [val.added * 1000, val.channel_count]),
|
||||||
capacity: data.map(val => [val.added * 1000, val.total_capacity]),
|
capacity: data.map(val => [val.added * 1000, val.total_capacity]),
|
||||||
});
|
});
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}),
|
}),
|
||||||
|
map((response) => {
|
||||||
|
return {
|
||||||
|
days: parseInt(response.headers.get('x-total-count'), 10),
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
).subscribe(() => {
|
)
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareChartOptions(data) {
|
prepareChartOptions(data) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user