mirror of
https://github.com/mempool/mempool.git
synced 2024-12-28 01:04:28 +01:00
Merge branch 'master' into mobile-refinements
This commit is contained in:
commit
d769226061
File diff suppressed because one or more lines are too long
@ -31,6 +31,7 @@ import { MiningDashboardComponent } from './components/mining-dashboard/mining-d
|
|||||||
import { HashrateChartComponent } from './components/hashrate-chart/hashrate-chart.component';
|
import { HashrateChartComponent } from './components/hashrate-chart/hashrate-chart.component';
|
||||||
import { HashrateChartPoolsComponent } from './components/hashrates-chart-pools/hashrate-chart-pools.component';
|
import { HashrateChartPoolsComponent } from './components/hashrates-chart-pools/hashrate-chart-pools.component';
|
||||||
import { MiningStartComponent } from './components/mining-start/mining-start.component';
|
import { MiningStartComponent } from './components/mining-start/mining-start.component';
|
||||||
|
import { GraphsComponent } from './components/graphs/graphs.component';
|
||||||
import { BlocksList } from './components/blocks-list/blocks-list.component';
|
import { BlocksList } from './components/blocks-list/blocks-list.component';
|
||||||
|
|
||||||
let routes: Routes = [
|
let routes: Routes = [
|
||||||
@ -80,18 +81,6 @@ let routes: Routes = [
|
|||||||
path: 'blocks',
|
path: 'blocks',
|
||||||
component: BlocksList,
|
component: BlocksList,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'hashrate',
|
|
||||||
component: HashrateChartComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'hashrate/pools',
|
|
||||||
component: HashrateChartPoolsComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'pools',
|
|
||||||
component: PoolRankingComponent,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'pool',
|
path: 'pool',
|
||||||
children: [
|
children: [
|
||||||
@ -105,7 +94,30 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'graphs',
|
path: 'graphs',
|
||||||
component: StatisticsComponent,
|
component: GraphsComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
pathMatch: 'full',
|
||||||
|
redirectTo: 'mempool',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mempool',
|
||||||
|
component: StatisticsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/hashrate-difficulty',
|
||||||
|
component: HashrateChartComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools-dominance',
|
||||||
|
component: HashrateChartPoolsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools',
|
||||||
|
component: PoolRankingComponent,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'about',
|
path: 'about',
|
||||||
@ -224,7 +236,30 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'graphs',
|
path: 'graphs',
|
||||||
component: StatisticsComponent,
|
component: GraphsComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
pathMatch: 'full',
|
||||||
|
redirectTo: 'mempool',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mempool',
|
||||||
|
component: StatisticsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/hashrate-difficulty',
|
||||||
|
component: HashrateChartComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools-dominance',
|
||||||
|
component: HashrateChartPoolsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools',
|
||||||
|
component: PoolRankingComponent,
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'address/:id',
|
path: 'address/:id',
|
||||||
@ -337,7 +372,30 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'graphs',
|
path: 'graphs',
|
||||||
component: StatisticsComponent,
|
component: GraphsComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
pathMatch: 'full',
|
||||||
|
redirectTo: 'mempool',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mempool',
|
||||||
|
component: StatisticsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/hashrate-difficulty',
|
||||||
|
component: HashrateChartComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools-dominance',
|
||||||
|
component: HashrateChartPoolsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools',
|
||||||
|
component: PoolRankingComponent,
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'address/:id',
|
path: 'address/:id',
|
||||||
@ -439,7 +497,30 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'graphs',
|
path: 'graphs',
|
||||||
component: StatisticsComponent,
|
component: GraphsComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
pathMatch: 'full',
|
||||||
|
redirectTo: 'mempool',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mempool',
|
||||||
|
component: StatisticsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/hashrate-difficulty',
|
||||||
|
component: HashrateChartComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools-dominance',
|
||||||
|
component: HashrateChartPoolsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools',
|
||||||
|
component: PoolRankingComponent,
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'address/:id',
|
path: 'address/:id',
|
||||||
@ -548,7 +629,30 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'graphs',
|
path: 'graphs',
|
||||||
component: StatisticsComponent,
|
component: GraphsComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
pathMatch: 'full',
|
||||||
|
redirectTo: 'mempool',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mempool',
|
||||||
|
component: StatisticsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/hashrate-difficulty',
|
||||||
|
component: HashrateChartComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools-dominance',
|
||||||
|
component: HashrateChartPoolsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mining/pools',
|
||||||
|
component: PoolRankingComponent,
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'address/:id',
|
path: 'address/:id',
|
||||||
|
@ -75,6 +75,7 @@ import { HashrateChartPoolsComponent } from './components/hashrates-chart-pools/
|
|||||||
import { MiningStartComponent } from './components/mining-start/mining-start.component';
|
import { MiningStartComponent } from './components/mining-start/mining-start.component';
|
||||||
import { AmountShortenerPipe } from './shared/pipes/amount-shortener.pipe';
|
import { AmountShortenerPipe } from './shared/pipes/amount-shortener.pipe';
|
||||||
import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe';
|
import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe';
|
||||||
|
import { GraphsComponent } from './components/graphs/graphs.component';
|
||||||
import { DifficultyAdjustmentsTable } from './components/difficulty-adjustments-table/difficulty-adjustments-table.components';
|
import { DifficultyAdjustmentsTable } from './components/difficulty-adjustments-table/difficulty-adjustments-table.components';
|
||||||
import { BlocksList } from './components/blocks-list/blocks-list.component';
|
import { BlocksList } from './components/blocks-list/blocks-list.component';
|
||||||
|
|
||||||
@ -133,6 +134,7 @@ import { BlocksList } from './components/blocks-list/blocks-list.component';
|
|||||||
HashrateChartPoolsComponent,
|
HashrateChartPoolsComponent,
|
||||||
MiningStartComponent,
|
MiningStartComponent,
|
||||||
AmountShortenerPipe,
|
AmountShortenerPipe,
|
||||||
|
GraphsComponent,
|
||||||
DifficultyAdjustmentsTable,
|
DifficultyAdjustmentsTable,
|
||||||
BlocksList,
|
BlocksList,
|
||||||
],
|
],
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<ng-template ngbNavContent>
|
<ng-template ngbNavContent>
|
||||||
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapCommonJS(code)"></app-clipboard></div>
|
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapCommonJS(code)"></app-clipboard></div>
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<a [href]="npmGithubLink()" target="_blank">github repository</a>
|
<a [href]="npmGithubLink()" target="_blank">GitHub Repo</a>
|
||||||
</div>
|
</div>
|
||||||
<pre><code [innerText]="wrapCommonJS(code)"></code></pre>
|
<pre><code [innerText]="wrapCommonJS(code)"></code></pre>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -22,8 +22,8 @@
|
|||||||
<ng-template ngbNavContent>
|
<ng-template ngbNavContent>
|
||||||
<div class="subtitle"><ng-container i18n="API Docs install lib">Install Package</ng-container> <app-clipboard [text]="wrapImportTemplate()"></app-clipboard></div>
|
<div class="subtitle"><ng-container i18n="API Docs install lib">Install Package</ng-container> <app-clipboard [text]="wrapImportTemplate()"></app-clipboard></div>
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<a [href]="npmGithubLink()" target="_blank">github repository</a>
|
<a [href]="npmGithubLink()" target="_blank">GitHub Repo</a>
|
||||||
<a [href]="npmModuleLink()" target="_blank">npm package</a>
|
<a [href]="npmModuleLink()" target="_blank">NPM Package</a>
|
||||||
</div>
|
</div>
|
||||||
<pre><code [innerText]="wrapImportTemplate()"></code></pre>
|
<pre><code [innerText]="wrapImportTemplate()"></code></pre>
|
||||||
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapEsModule(code)"></app-clipboard></div>
|
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapEsModule(code)"></app-clipboard></div>
|
||||||
|
25
frontend/src/app/components/graphs/graphs.component.html
Normal file
25
frontend/src/app/components/graphs/graphs.component.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<ul ngbNav #nav="ngbNav" class="nav-pills mb-3" style="padding: 0px 35px">
|
||||||
|
<div class="d-inline-flex flex-wrap menu">
|
||||||
|
<li ngbNavItem class="menu-li">
|
||||||
|
<a routerLinkActive="active" [routerLink]="['/graphs/mempool' | relativeUrl]" ngbNavLink>Mempool</a>
|
||||||
|
</li>
|
||||||
|
<li ngbNavItem class="menu-li">
|
||||||
|
<a routerLinkActive="active" [routerLink]="['/graphs/mining/pools' | relativeUrl]" ngbNavLink i18n="mining.pools">
|
||||||
|
Pools ranking
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ngbNavItem class="menu-li">
|
||||||
|
<a routerLinkActive="active" [routerLink]="['/graphs/mining/pools-dominance' | relativeUrl]" ngbNavLink i18n="mining.pools-dominance">
|
||||||
|
Pools dominance
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li ngbNavItem class="menu-li">
|
||||||
|
<a routerLinkActive="active" [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" ngbNavLink
|
||||||
|
i18n="mining.hashrate-difficulty">
|
||||||
|
Hashrate & Difficulty
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<router-outlet></router-outlet>
|
9
frontend/src/app/components/graphs/graphs.component.scss
Normal file
9
frontend/src/app/components/graphs/graphs.component.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.menu {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-li {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
14
frontend/src/app/components/graphs/graphs.component.ts
Normal file
14
frontend/src/app/components/graphs/graphs.component.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-graphs',
|
||||||
|
templateUrl: './graphs.component.html',
|
||||||
|
styleUrls: ['./graphs.component.scss'],
|
||||||
|
})
|
||||||
|
export class GraphsComponent implements OnInit {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,25 @@
|
|||||||
<div [class]="widget === false ? 'full-container' : ''">
|
<div [class]="widget === false ? 'full-container' : ''">
|
||||||
|
|
||||||
|
<div *ngIf="widget">
|
||||||
|
<div class="pool-distribution" *ngIf="(hashrateObservable$ | async) as hashrates; else loadingStats">
|
||||||
|
<div class="item">
|
||||||
|
<h5 class="card-title" i18n="mining.hashrate">Hashrate</h5>
|
||||||
|
<p class="card-text">
|
||||||
|
{{ hashrates.currentHashrate | amountShortener }}
|
||||||
|
<span class="symbol">hashes/sec</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<h5 class="card-title" i18n="master-page.blocks">Difficulty</h5>
|
||||||
|
<p class="card-text">
|
||||||
|
{{ hashrates.currentDifficulty | amountShortener }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
||||||
|
<span i18n="mining.mining-pool-share">Hashrate & Difficulty</span>
|
||||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
|
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
|
||||||
<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="hashrates.availableTimespanDay >= 90">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
|
||||||
@ -32,3 +51,20 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ng-template #loadingStats>
|
||||||
|
<div class="pool-distribution">
|
||||||
|
<div class="item">
|
||||||
|
<h5 class="card-title" i18n="mining.miners-luck">Hashrate</h5>
|
||||||
|
<p class="card-text">
|
||||||
|
<span class="skeleton-loader skeleton-loader-big"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<h5 class="card-title" i18n="master-page.blocks">Difficulty</h5>
|
||||||
|
<p class="card-text">
|
||||||
|
<span class="skeleton-loader skeleton-loader-big"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
@ -1,3 +1,11 @@
|
|||||||
|
.card-header {
|
||||||
|
border-bottom: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
@media (min-width: 465px) {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: #ffffff91;
|
color: #ffffff91;
|
||||||
@ -10,13 +18,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.full-container {
|
.full-container {
|
||||||
|
padding: 0px 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 100px);
|
height: calc(100% - 170px);
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
height: calc(100% - 140px);
|
height: calc(100% - 220px);
|
||||||
};
|
};
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 575px) {
|
||||||
height: calc(100% - 180px);
|
height: calc(100% - 260px);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,18 +33,41 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
padding-right: 20px;
|
padding-right: 10px;
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
padding-bottom: 25px;
|
||||||
|
}
|
||||||
|
@media (max-width: 829px) {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
padding-bottom: 25px;
|
||||||
|
}
|
||||||
|
@media (max-width: 629px) {
|
||||||
|
padding-bottom: 55px;
|
||||||
|
}
|
||||||
|
@media (max-width: 567px) {
|
||||||
|
padding-bottom: 55px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.chart-widget {
|
.chart-widget {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
max-height: 293px;
|
max-height: 270px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.formRadioGroup {
|
.formRadioGroup {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@media (min-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: -65px;
|
||||||
|
}
|
||||||
|
@media (min-width: 830px) and (max-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
@media (min-width: 830px) {
|
@media (min-width: 830px) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
float: right;
|
float: right;
|
||||||
@ -48,3 +80,66 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pool-distribution {
|
||||||
|
min-height: 56px;
|
||||||
|
display: block;
|
||||||
|
@media (min-width: 485px) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
h5 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
width: 50%;
|
||||||
|
margin: 0px auto 10px;
|
||||||
|
display: inline-block;
|
||||||
|
@media (min-width: 485px) {
|
||||||
|
margin: 0px auto 10px;
|
||||||
|
}
|
||||||
|
@media (min-width: 785px) {
|
||||||
|
margin: 0px auto 0px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin: 0px auto 0px;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
order: 2;
|
||||||
|
@media (min-width: 485px) {
|
||||||
|
order: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:nth-child(3) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
.card-text {
|
||||||
|
font-size: 18px;
|
||||||
|
span {
|
||||||
|
color: #ffffff66;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-loader {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
max-width: 80px;
|
||||||
|
margin: 15px auto 3px;
|
||||||
|
}
|
||||||
|
@ -61,6 +61,7 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
.pipe(
|
.pipe(
|
||||||
startWith('1y'),
|
startWith('1y'),
|
||||||
switchMap((timespan) => {
|
switchMap((timespan) => {
|
||||||
|
this.isLoading = true;
|
||||||
return this.apiService.getHistoricalHashrate$(timespan)
|
return this.apiService.getHistoricalHashrate$(timespan)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((data: any) => {
|
tap((data: any) => {
|
||||||
@ -109,21 +110,10 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
|
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
|
||||||
) / 3600 / 24;
|
) / 3600 / 24;
|
||||||
|
|
||||||
const tableData = [];
|
|
||||||
for (let i = data.difficulty.length - 1; i > 0; --i) {
|
|
||||||
const selectedPowerOfTen: any = selectPowerOfTen(data.difficulty[i].difficulty);
|
|
||||||
const change = (data.difficulty[i].difficulty / data.difficulty[i - 1].difficulty - 1) * 100;
|
|
||||||
|
|
||||||
tableData.push(Object.assign(data.difficulty[i], {
|
|
||||||
change: change,
|
|
||||||
difficultyShorten: formatNumber(
|
|
||||||
data.difficulty[i].difficulty / selectedPowerOfTen.divider,
|
|
||||||
this.locale, '1.2-2') + selectedPowerOfTen.unit
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
availableTimespanDay: availableTimespanDay,
|
availableTimespanDay: availableTimespanDay,
|
||||||
difficulty: this.tableOnly ? tableData.slice(0, 5) : tableData,
|
currentDifficulty: Math.round(data.difficulty[data.difficulty.length - 1].difficulty * 100) / 100,
|
||||||
|
currentHashrate: data.hashrates[data.hashrates.length - 1].avgHashrate,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
retryWhen((errors) => errors.pipe(
|
retryWhen((errors) => errors.pipe(
|
||||||
@ -155,6 +145,7 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
|
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
title: title,
|
title: title,
|
||||||
|
animation: false,
|
||||||
color: [
|
color: [
|
||||||
new graphic.LinearGradient(0, 0, 0, 0.65, [
|
new graphic.LinearGradient(0, 0, 0, 0.65, [
|
||||||
{ offset: 0, color: '#F4511E' },
|
{ offset: 0, color: '#F4511E' },
|
||||||
@ -166,9 +157,10 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
'#D81B60',
|
'#D81B60',
|
||||||
],
|
],
|
||||||
grid: {
|
grid: {
|
||||||
|
top: 30,
|
||||||
right: this.right,
|
right: this.right,
|
||||||
left: this.left,
|
left: this.left,
|
||||||
bottom: this.widget ? 30 : 60,
|
bottom: this.widget ? 30 : this.isMobile() ? 90 : 60,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: !this.isMobile() || !this.widget,
|
show: !this.isMobile() || !this.widget,
|
||||||
@ -209,7 +201,7 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
type: 'time',
|
type: 'time',
|
||||||
splitNumber: (this.isMobile() || this.widget) ? 5 : 10,
|
splitNumber: (this.isMobile() || this.widget) ? 5 : 10,
|
||||||
},
|
},
|
||||||
legend: data.hashrates.length === 0 ? undefined : {
|
legend: (this.widget || data.hashrates.length === 0) ? undefined : {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: 'Hashrate',
|
name: 'Hashrate',
|
||||||
@ -241,7 +233,6 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
return value.min * 0.9;
|
return value.min * 0.9;
|
||||||
},
|
},
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: 'Hashrate',
|
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: 'rgb(110, 112, 121)',
|
color: 'rgb(110, 112, 121)',
|
||||||
formatter: (val) => {
|
formatter: (val) => {
|
||||||
@ -259,7 +250,6 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
return value.min * 0.9;
|
return value.min * 0.9;
|
||||||
},
|
},
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: 'Difficulty',
|
|
||||||
position: 'right',
|
position: 'right',
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: 'rgb(110, 112, 121)',
|
color: 'rgb(110, 112, 121)',
|
||||||
@ -301,17 +291,18 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
type: 'inside',
|
type: 'inside',
|
||||||
realtime: true,
|
realtime: true,
|
||||||
zoomLock: true,
|
zoomLock: true,
|
||||||
zoomOnMouseWheel: true,
|
|
||||||
moveOnMouseMove: true,
|
|
||||||
maxSpan: 100,
|
maxSpan: 100,
|
||||||
minSpan: 10,
|
minSpan: 10,
|
||||||
|
moveOnMouseMove: false,
|
||||||
}, {
|
}, {
|
||||||
showDetail: false,
|
showDetail: false,
|
||||||
show: true,
|
show: true,
|
||||||
type: 'slider',
|
type: 'slider',
|
||||||
brushSelect: false,
|
brushSelect: false,
|
||||||
realtime: true,
|
realtime: true,
|
||||||
bottom: 0,
|
bottom: this.isMobile() ? 30 : 0,
|
||||||
|
left: 20,
|
||||||
|
right: 15,
|
||||||
selectedDataBackground: {
|
selectedDataBackground: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<div [class]="widget === false ? 'full-container' : ''">
|
<div [class]="widget === false ? 'full-container' : ''">
|
||||||
|
|
||||||
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
<div class="card-header" [style]="widget ? 'display:none' : ''">
|
||||||
|
<span *ngIf="!widget" i18n="mining.pools-dominance">Mining pools dominance</span>
|
||||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
|
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
|
||||||
<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="hashrates.availableTimespanDay >= 90">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
.card-header {
|
||||||
|
border-bottom: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
@media (min-width: 465px) {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: #ffffff91;
|
color: #ffffff91;
|
||||||
@ -10,21 +18,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.full-container {
|
.full-container {
|
||||||
|
padding: 0px 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 100px);
|
height: calc(100% - 140px);
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 991px) {
|
||||||
height: calc(100% - 140px);
|
height: calc(100% - 190px);
|
||||||
};
|
};
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 575px) {
|
||||||
height: calc(100% - 180px);
|
height: calc(100% - 235px);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart {
|
.chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 25px;
|
||||||
padding-right: 20px;
|
padding-right: 10px;
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
padding-bottom: 25px;
|
||||||
|
}
|
||||||
|
@media (max-width: 829px) {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
@media (max-width: 629px) {
|
||||||
|
padding-bottom: 85px;
|
||||||
|
}
|
||||||
|
@media (max-width: 567px) {
|
||||||
|
padding-bottom: 85px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.chart-widget {
|
.chart-widget {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -36,6 +60,14 @@
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@media (min-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: -65px;
|
||||||
|
}
|
||||||
|
@media (min-width: 830px) and (max-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
@media (min-width: 830px) {
|
@media (min-width: 830px) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -23,7 +23,7 @@ import { poolsColor } from 'src/app/app.constants';
|
|||||||
})
|
})
|
||||||
export class HashrateChartPoolsComponent implements OnInit {
|
export class HashrateChartPoolsComponent implements OnInit {
|
||||||
@Input() widget = false;
|
@Input() widget = false;
|
||||||
@Input() right: number | string = 40;
|
@Input() right: number | string = 45;
|
||||||
@Input() left: number | string = 25;
|
@Input() left: number | string = 25;
|
||||||
|
|
||||||
radioGroupForm: FormGroup;
|
radioGroupForm: FormGroup;
|
||||||
@ -153,11 +153,12 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
|
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
title: title,
|
title: title,
|
||||||
|
animation: false,
|
||||||
grid: {
|
grid: {
|
||||||
right: this.right,
|
right: this.right,
|
||||||
left: this.left,
|
left: this.left,
|
||||||
bottom: this.widget ? 30 : 20,
|
bottom: this.widget ? 30 : 60,
|
||||||
top: this.widget ? 10 : 40,
|
top: this.widget || this.isMobile() ? 10 : 50,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: !this.isMobile() || !this.widget,
|
show: !this.isMobile() || !this.widget,
|
||||||
@ -206,6 +207,32 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
min: 0,
|
min: 0,
|
||||||
},
|
},
|
||||||
series: data.series,
|
series: data.series,
|
||||||
|
dataZoom: this.widget ? null : [{
|
||||||
|
type: 'inside',
|
||||||
|
realtime: true,
|
||||||
|
zoomLock: true,
|
||||||
|
maxSpan: 100,
|
||||||
|
minSpan: 10,
|
||||||
|
moveOnMouseMove: false,
|
||||||
|
}, {
|
||||||
|
showDetail: false,
|
||||||
|
show: true,
|
||||||
|
type: 'slider',
|
||||||
|
brushSelect: false,
|
||||||
|
realtime: true,
|
||||||
|
bottom: 0,
|
||||||
|
left: 20,
|
||||||
|
right: 15,
|
||||||
|
selectedDataBackground: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
opacity: 0.45,
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<a class="nav-link" [routerLink]="['/blocks' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" i18n-title="master-page.blocks" title="Blocks"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/blocks' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" i18n-title="master-page.blocks" title="Blocks"></fa-icon></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" routerLinkActive="active" id="btn-graphs">
|
<li class="nav-item" routerLinkActive="active" id="btn-graphs">
|
||||||
<a class="nav-link" [routerLink]="['/graphs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'chart-area']" [fixedWidth]="true" i18n-title="master-page.graphs" title="Graphs"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/graphs/mempool' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'chart-area']" [fixedWidth]="true" i18n-title="master-page.graphs" title="Graphs"></fa-icon></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item d-none d-lg-block" routerLinkActive="active" id="btn-tv">
|
<li class="nav-item d-none d-lg-block" routerLinkActive="active" id="btn-tv">
|
||||||
<a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon></a>
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
<div class="card" style="height: 385px">
|
<div class="card" style="height: 385px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<app-pool-ranking [widget]=true></app-pool-ranking>
|
<app-pool-ranking [widget]=true></app-pool-ranking>
|
||||||
<div class="mt-1"><a [routerLink]="['/mining/pools' | relativeUrl]" i18n="dashboard.view-more">View more
|
<div class="mt-1"><a [routerLink]="['/graphs/mining/pools' | relativeUrl]" i18n="dashboard.view-more">View more
|
||||||
»</a></div>
|
»</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -86,30 +86,13 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card" style="height: 385px">
|
<div class="card" style="height: 385px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">
|
|
||||||
Hashrate (1y)
|
|
||||||
</h5>
|
|
||||||
<app-hashrate-chart [widget]=true></app-hashrate-chart>
|
<app-hashrate-chart [widget]=true></app-hashrate-chart>
|
||||||
<div class="mt-1"><a [routerLink]="['/mining/hashrate' | relativeUrl]" i18n="dashboard.view-more">View more
|
<div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" i18n="dashboard.view-more">View more
|
||||||
»</a></div>
|
»</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- pool dominance -->
|
|
||||||
<!-- <div class="col">
|
|
||||||
<div class="card" style="height: 385px">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">
|
|
||||||
Mining Pools Dominance (1y)
|
|
||||||
</h5>
|
|
||||||
<app-hashrate-chart-pools [widget]=true></app-hashrate-chart-pools>
|
|
||||||
<div class="mt-1"><a [routerLink]="['/mining/hashrate/pools' | relativeUrl]" i18n="dashboard.view-more">View
|
|
||||||
more »</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- Latest blocks -->
|
<!-- Latest blocks -->
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card" style="height: 385px">
|
<div class="card" style="height: 385px">
|
||||||
@ -124,6 +107,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Difficult adjustments -->
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card" style="height: 385px">
|
<div class="card" style="height: 385px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -131,11 +115,11 @@
|
|||||||
Adjustments
|
Adjustments
|
||||||
</h5>
|
</h5>
|
||||||
<app-difficulty-adjustments-table></app-difficulty-adjustments-table>
|
<app-difficulty-adjustments-table></app-difficulty-adjustments-table>
|
||||||
<div><a [routerLink]="['/mining/hashrate' | relativeUrl]" i18n="dashboard.view-more">View more
|
<div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" i18n="dashboard.view-more">View more
|
||||||
»</a></div>
|
»</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -125,3 +125,7 @@
|
|||||||
max-width: 55px;
|
max-width: 55px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-text {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, OnInit } from '@angular/core';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { SeoService } from 'src/app/services/seo.service';
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
import { StateService } from 'src/app/services/state.service';
|
import { StateService } from 'src/app/services/state.service';
|
||||||
|
import { formatNumber } from '@angular/common';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div [class]="widget === false ? 'container-xl' : ''">
|
<div [class]="widget === false ? 'full-container' : ''">
|
||||||
|
|
||||||
<div *ngIf="widget">
|
<div *ngIf="widget">
|
||||||
<div class="pool-distribution" *ngIf="(miningStatsObservable$ | async) as miningStats; else loadingReward">
|
<div class="pool-distribution" *ngIf="(miningStatsObservable$ | async) as miningStats; else loadingReward">
|
||||||
@ -23,14 +23,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [class]="widget ? 'chart-widget' : 'chart'"
|
<div class="card-header" *ngIf="!widget">
|
||||||
echarts [initOpts]="chartInitOptions" [options]="chartOptions" (chartInit)="onChartInit($event)"></div>
|
<span i18n="mining.mining-pool-share">Mining pools share</span>
|
||||||
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
<form [formGroup]="radioGroupForm" class="formRadioGroup"
|
||||||
<div class="spinner-border text-light"></div>
|
*ngIf="!widget && (miningStatsObservable$ | async) as miningStats">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-header mb-0 mb-lg-4 mt-md-3" [style]="widget ? 'display:none' : ''">
|
|
||||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(miningStatsObservable$ | async) as miningStats">
|
|
||||||
<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="miningStats.availableTimespanDay >= 1">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 1">
|
||||||
<input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
|
<input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
|
||||||
@ -66,36 +62,48 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table *ngIf="widget === false" class="table table-borderless text-center pools-table">
|
<div [class]="!widget ? 'bottom-padding' : 'pb-0'" class="container pb-lg-0">
|
||||||
<thead>
|
<div [class]="widget ? 'chart-widget' : 'chart'" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
|
||||||
<tr>
|
(chartInit)="onChartInit($event)"></div>
|
||||||
<th class="d-none d-md-block" i18n="mining.rank">Rank</th>
|
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
||||||
<th class=""></th>
|
<div class="spinner-border text-light"></div>
|
||||||
<th class="" i18n="mining.pool-name">Pool</th>
|
</div>
|
||||||
<th class="" *ngIf="this.poolsWindowPreference === '24h'" i18n="mining.hashrate">Hashrate</th>
|
|
||||||
<th class="" i18n="master-page.blocks">Blocks</th>
|
<table *ngIf="widget === false" class="table table-borderless text-center pools-table">
|
||||||
<th class="d-none d-md-block" i18n="mining.empty-blocks">Empty Blocks</th>
|
<thead>
|
||||||
</tr>
|
<tr>
|
||||||
</thead>
|
<th class="d-none d-md-block" i18n="mining.rank">Rank</th>
|
||||||
<tbody *ngIf="(miningStatsObservable$ | async) as miningStats">
|
<th class=""></th>
|
||||||
<tr *ngFor="let pool of miningStats.pools">
|
<th class="" i18n="mining.pool-name">Pool</th>
|
||||||
<td class="d-none d-md-block">{{ pool.rank }}</td>
|
<th class="" *ngIf="this.poolsWindowPreference === '24h'" i18n="mining.hashrate">Hashrate</th>
|
||||||
<td class="text-right"><img width="25" height="25" src="{{ pool.logo }}" onError="this.src = './resources/mining-pools/default.svg'"></td>
|
<th class="" i18n="master-page.blocks">Blocks</th>
|
||||||
<td class=""><a [routerLink]="[('/mining/pool/' + pool.poolId) | relativeUrl]">{{ pool.name }}</a></td>
|
<th class="d-none d-md-block" i18n="mining.empty-blocks">Empty Blocks</th>
|
||||||
<td class="" *ngIf="this.poolsWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{ miningStats.miningUnits.hashrateUnit }}</td>
|
</tr>
|
||||||
<td class="">{{ pool['blockText'] }}</td>
|
</thead>
|
||||||
<td class="d-none d-md-block">{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%)</td>
|
<tbody *ngIf="(miningStatsObservable$ | async) as miningStats">
|
||||||
</tr>
|
<tr *ngFor="let pool of miningStats.pools">
|
||||||
<tr style="border-top: 1px solid #555">
|
<td class="d-none d-md-block">{{ pool.rank }}</td>
|
||||||
<td class="d-none d-md-block"></td>
|
<td class="text-right"><img width="25" height="25" src="{{ pool.logo }}"
|
||||||
<td class="text-right"></td>
|
onError="this.src = './resources/mining-pools/default.svg'"></td>
|
||||||
<td class="" i18n="mining.all-miners"><b>All miners</b></td>
|
<td class=""><a [routerLink]="[('/mining/pool/' + pool.poolId) | relativeUrl]">{{ pool.name }}</a></td>
|
||||||
<td class="" *ngIf="this.poolsWindowPreference === '24h'"><b>{{ miningStats.lastEstimatedHashrate}} {{ miningStats.miningUnits.hashrateUnit }}</b></td>
|
<td class="" *ngIf="this.poolsWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{
|
||||||
<td class=""><b>{{ miningStats.blockCount }}</b></td>
|
miningStats.miningUnits.hashrateUnit }}</td>
|
||||||
<td class="d-none d-md-block"><b>{{ miningStats.totalEmptyBlock }} ({{ miningStats.totalEmptyBlockRatio }}%)</b></td>
|
<td class="">{{ pool['blockText'] }}</td>
|
||||||
</tr>
|
<td class="d-none d-md-block">{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%)</td>
|
||||||
</tbody>
|
</tr>
|
||||||
</table>
|
<tr style="border-top: 1px solid #555">
|
||||||
|
<td class="d-none d-md-block"></td>
|
||||||
|
<td class="text-right"></td>
|
||||||
|
<td class="" i18n="mining.all-miners"><b>All miners</b></td>
|
||||||
|
<td class="" *ngIf="this.poolsWindowPreference === '24h'"><b>{{ miningStats.lastEstimatedHashrate}} {{
|
||||||
|
miningStats.miningUnits.hashrateUnit }}</b></td>
|
||||||
|
<td class=""><b>{{ miningStats.blockCount }}</b></td>
|
||||||
|
<td class="d-none d-md-block"><b>{{ miningStats.totalEmptyBlock }} ({{ miningStats.totalEmptyBlockRatio
|
||||||
|
}}%)</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -121,4 +129,4 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -1,7 +1,27 @@
|
|||||||
|
.card-header {
|
||||||
|
border-bottom: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
@media (min-width: 465px) {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-container {
|
||||||
|
padding: 0px 15px;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 140px);
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
height: calc(100% - 190px);
|
||||||
|
};
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
height: calc(100% - 230px);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
.chart {
|
.chart {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
max-height: 270px;
|
max-height: 230px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.chart-widget {
|
.chart-widget {
|
||||||
@ -17,10 +37,17 @@
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@media (min-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: -65px;
|
||||||
|
}
|
||||||
|
@media (min-width: 830px) and (max-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
@media (min-width: 830px) {
|
@media (min-width: 830px) {
|
||||||
margin-left: 2%;
|
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
float: left;
|
float: right;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
.btn-sm {
|
.btn-sm {
|
||||||
@ -31,12 +58,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
.bottom-padding {
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
padding-bottom: 65px
|
||||||
|
};
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
padding-bottom: 65px
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
.pools-table th,
|
.pools-table th,
|
||||||
.pools-table td {
|
.pools-table td {
|
||||||
padding: .3em !important;
|
padding: .3em !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loadingGraphs {
|
.loadingGraphs {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -44,9 +80,6 @@
|
|||||||
left: calc(50% - 15px);
|
left: calc(50% - 15px);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
.loadingGraphs.widget {
|
|
||||||
top: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pool-distribution {
|
.pool-distribution {
|
||||||
min-height: 56px;
|
min-height: 56px;
|
||||||
|
@ -117,7 +117,7 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
if (this.isMobile() && this.widget) {
|
if (this.isMobile() && this.widget) {
|
||||||
edgeDistance = 0;
|
edgeDistance = 0;
|
||||||
} else if (this.isMobile() && !this.widget || this.widget) {
|
} else if (this.isMobile() && !this.widget || this.widget) {
|
||||||
edgeDistance = 35;
|
edgeDistance = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
miningStats.pools.forEach((pool) => {
|
miningStats.pools.forEach((pool) => {
|
||||||
@ -209,13 +209,13 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
network = network.charAt(0).toUpperCase() + network.slice(1);
|
network = network.charAt(0).toUpperCase() + network.slice(1);
|
||||||
|
|
||||||
let radius: any[] = ['20%', '80%'];
|
let radius: any[] = ['20%', '80%'];
|
||||||
let top: any = undefined; let bottom = undefined; let height = undefined;
|
let top: number = 0; let height = undefined;
|
||||||
if (this.isMobile() && this.widget) {
|
if (this.isMobile() && this.widget) {
|
||||||
top = -30;
|
top = -30;
|
||||||
height = 270;
|
height = 270;
|
||||||
radius = ['10%', '50%'];
|
radius = ['10%', '50%'];
|
||||||
} else if (this.isMobile() && !this.widget) {
|
} else if (this.isMobile() && !this.widget) {
|
||||||
top = 0;
|
top = -40;
|
||||||
height = 300;
|
height = 300;
|
||||||
radius = ['10%', '50%'];
|
radius = ['10%', '50%'];
|
||||||
} else if (this.widget) {
|
} else if (this.widget) {
|
||||||
@ -223,22 +223,12 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
top = -20;
|
top = -20;
|
||||||
height = 330;
|
height = 330;
|
||||||
} else {
|
} else {
|
||||||
top = 35;
|
top = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
|
animation: false,
|
||||||
color: chartColors,
|
color: chartColors,
|
||||||
title: {
|
|
||||||
text: this.widget ? '' : $localize`:@@mining.pool-chart-title:${network}:NETWORK: mining pools share`,
|
|
||||||
left: 'center',
|
|
||||||
textStyle: {
|
|
||||||
color: '#FFF',
|
|
||||||
},
|
|
||||||
subtextStyle: {
|
|
||||||
color: '#CCC',
|
|
||||||
fontStyle: 'italic',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
@ -249,7 +239,6 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
{
|
{
|
||||||
minShowLabelAngle: 3.6,
|
minShowLabelAngle: 3.6,
|
||||||
top: top,
|
top: top,
|
||||||
bottom: bottom,
|
|
||||||
height: height,
|
height: height,
|
||||||
name: 'Mining pool',
|
name: 'Mining pool',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
|
||||||
import { StateService } from 'src/app/services/state.service';
|
import { StateService } from 'src/app/services/state.service';
|
||||||
import { specialBlocks } from 'src/app/app.constants';
|
import { specialBlocks } from 'src/app/app.constants';
|
||||||
|
|
||||||
@ -20,12 +19,10 @@ export class StartComponent implements OnInit {
|
|||||||
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private websocketService: WebsocketService,
|
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.websocketService.want(['blocks', 'stats', 'mempool-blocks']);
|
|
||||||
this.stateService.blocks$
|
this.stateService.blocks$
|
||||||
.subscribe((blocks: any) => {
|
.subscribe((blocks: any) => {
|
||||||
if (this.stateService.network !== '') {
|
if (this.stateService.network !== '') {
|
||||||
|
@ -40,6 +40,14 @@
|
|||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@media (min-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: -65px;
|
||||||
|
}
|
||||||
|
@media (min-width: 830px) and (max-width: 1130px) {
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
@media (min-width: 830px) {
|
@media (min-width: 830px) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -1,39 +1,26 @@
|
|||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
// https://medium.com/@thunderroid/angular-short-number-suffix-pipe-1k-2m-3b-dded4af82fb4
|
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'amountShortener'
|
name: 'amountShortener'
|
||||||
})
|
})
|
||||||
export class AmountShortenerPipe implements PipeTransform {
|
export class AmountShortenerPipe implements PipeTransform {
|
||||||
transform(number: number, args?: any): any {
|
transform(num: number, ...args: number[]): unknown {
|
||||||
if (isNaN(number)) return null; // will only work value is a number
|
if (num < 1000) {
|
||||||
if (number === null) return null;
|
return num;
|
||||||
if (number === 0) return null;
|
|
||||||
let abs = Math.abs(number);
|
|
||||||
const rounder = Math.pow(10, 1);
|
|
||||||
const isNegative = number < 0; // will also work for Negetive numbers
|
|
||||||
let key = '';
|
|
||||||
|
|
||||||
const powers = [
|
|
||||||
{ key: 'E', value: 10e18 },
|
|
||||||
{ key: 'P', value: 10e15 },
|
|
||||||
{ key: 'T', value: 10e12 },
|
|
||||||
{ key: 'B', value: 10e9 },
|
|
||||||
{ key: 'M', value: 10e6 },
|
|
||||||
{ key: 'K', value: 1000 }
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i = 0; i < powers.length; i++) {
|
|
||||||
let reduced = abs / powers[i].value;
|
|
||||||
reduced = Math.round(reduced * rounder) / rounder;
|
|
||||||
if (reduced >= 1) {
|
|
||||||
abs = reduced;
|
|
||||||
key = powers[i].key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (isNegative ? '-' : '') + abs + key;
|
const digits = args[0] || 1;
|
||||||
|
const lookup = [
|
||||||
|
{ value: 1, symbol: '' },
|
||||||
|
{ value: 1e3, symbol: 'k' },
|
||||||
|
{ value: 1e6, symbol: 'M' },
|
||||||
|
{ value: 1e9, symbol: 'G' },
|
||||||
|
{ value: 1e12, symbol: 'T' },
|
||||||
|
{ value: 1e15, symbol: 'P' },
|
||||||
|
{ value: 1e18, symbol: 'E' }
|
||||||
|
];
|
||||||
|
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||||
|
var item = lookup.slice().reverse().find((item) => num >= item.value);
|
||||||
|
return item ? (num / item.value).toFixed(digits).replace(rx, '$1') + item.symbol : '0';
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user