diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index fd7ab3a3d..3e2c40b25 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -46,6 +46,7 @@ import { SharedModule } from './shared/shared.module'; import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; import { FeesBoxComponent } from './components/fees-box/fees-box.component'; import { DashboardComponent } from './dashboard/dashboard.component'; +import { DifficultyComponent } from './components/difficulty/difficulty.component'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl } from '@fortawesome/free-solid-svg-icons'; @@ -97,6 +98,7 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; StatusViewComponent, FeesBoxComponent, DashboardComponent, + DifficultyComponent, ApiDocsComponent, CodeTemplateComponent, TermsOfServiceComponent, diff --git a/frontend/src/app/components/difficulty/difficulty.component.html b/frontend/src/app/components/difficulty/difficulty.component.html new file mode 100644 index 000000000..5064c1c08 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty.component.html @@ -0,0 +1,78 @@ +
Difficulty Adjustment
+
+
+
+
+
+
Remaining
+
+ + {{ i }} blocks + {{ i }} block +
+
+
+
+
Estimate
+
+ + + + + + + {{ epochData.change | absolute | number: '1.2-2' }} + % +
+ +
+
+
+ Previous: + + + + + + + + {{ epochData.previousRetarget | absolute | number: '1.2-2' }} % +
+
+
+
Current Period
+
{{ epochData.progress | number: '1.2-2' }} %
+
+
 
+
+
+
+
+
+
+ + +
+
+
Remaining
+
+
+
+
+
+
+
Estimate
+
+
+
+
+
+
+
Current Period
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/difficulty/difficulty.component.scss b/frontend/src/app/components/difficulty/difficulty.component.scss new file mode 100644 index 000000000..f66e2c8e5 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty.component.scss @@ -0,0 +1,150 @@ +.difficulty-adjustment-container { + display: flex; + flex-direction: row; + justify-content: space-around; + height: 76px; + .shared-block { + color: #ffffff66; + font-size: 12px; + } + .item { + padding: 0 5px; + width: 100%; + &:nth-child(1) { + display: none; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } + } + .card-text { + font-size: 22px; + margin-top: -9px; + position: relative; + } +} + + +.difficulty-skeleton { + display: flex; + justify-content: space-between; + @media (min-width: 376px) { + flex-direction: row; + } + .item { + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; + } + &:first-child{ + display: none; + @media (min-width: 485px) { + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + &:last-child { + margin-bottom: 0; + } + } + .card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + margin: 14px auto 0; + max-width: 80px; + } + &:last-child { + margin: 10px auto 0; + max-width: 120px; + } + } + } +} + +.card { + background-color: #1d1f31; + height: 100%; +} + +.card-title { + color: #4a68b9; + font-size: 1rem; +} + +.progress { + display: inline-flex; + width: 100%; + background-color: #2d3348; + height: 1.1rem; + max-width: 180px; +} + +.skeleton-loader { + max-width: 100%; +} + +.more-padding { + padding: 18px; +} + +.small-bar { + height: 8px; + top: -4px; + max-width: 120px; +} + +.loading-container { + min-height: 76px; +} + +.main-title { + position: relative; + color: #ffffff91; + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 22px 20px; + } +} + +.retarget-sign { + margin-right: -3px; + font-size: 14px; + top: -2px; + position: relative; +} + +.previous-retarget-sign { + margin-right: -2px; + font-size: 10px; +} diff --git a/frontend/src/app/components/difficulty/difficulty.component.ts b/frontend/src/app/components/difficulty/difficulty.component.ts new file mode 100644 index 000000000..312c1b2d0 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty.component.ts @@ -0,0 +1,111 @@ +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { combineLatest, Observable, timer } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { StateService } from '../..//services/state.service'; + +interface EpochProgress { + base: string; + change: number; + progress: string; + remainingBlocks: number; + newDifficultyHeight: number; + colorAdjustments: string; + colorPreviousAdjustments: string; + timeAvg: string; + remainingTime: number; + previousRetarget: number; +} + +@Component({ + selector: 'app-difficulty', + templateUrl: './difficulty.component.html', + styleUrls: ['./difficulty.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DifficultyComponent implements OnInit { + isLoadingWebSocket$: Observable; + difficultyEpoch$: Observable; + + constructor( + public stateService: StateService, + ) { } + + ngOnInit(): void { + this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$; + this.difficultyEpoch$ = timer(0, 1000) + .pipe( + switchMap(() => combineLatest([ + this.stateService.blocks$.pipe(map(([block]) => block)), + this.stateService.lastDifficultyAdjustment$, + this.stateService.previousRetarget$ + ])), + map(([block, DATime, previousRetarget]) => { + const now = new Date().getTime() / 1000; + const diff = now - DATime; + const blocksInEpoch = block.height % 2016; + const progress = (blocksInEpoch >= 0) ? (blocksInEpoch / 2016 * 100).toFixed(2) : `100`; + const remainingBlocks = 2016 - blocksInEpoch; + const newDifficultyHeight = block.height + remainingBlocks; + + let change = 0; + if (remainingBlocks < 1870) { + if (blocksInEpoch > 0) { + change = (600 / (diff / blocksInEpoch ) - 1) * 100; + } + if (change > 300) { + change = 300; + } + if (change < -75) { + change = -75; + } + } + + const timeAvgDiff = change * 0.1; + + let timeAvgMins = 10; + if (timeAvgDiff > 0) { + timeAvgMins -= Math.abs(timeAvgDiff); + } else { + timeAvgMins += Math.abs(timeAvgDiff); + } + + const timeAvg = timeAvgMins.toFixed(0); + const remainingTime = (remainingBlocks * timeAvgMins * 60 * 1000) + (now * 1000); + + let colorAdjustments = '#ffffff66'; + if (change > 0) { + colorAdjustments = '#3bcc49'; + } + if (change < 0) { + colorAdjustments = '#dc3545'; + } + + let colorPreviousAdjustments = '#dc3545'; + if (previousRetarget) { + if (previousRetarget >= 0) { + colorPreviousAdjustments = '#3bcc49'; + } + if (previousRetarget === 0) { + colorPreviousAdjustments = '#ffffff66'; + } + } else { + colorPreviousAdjustments = '#ffffff66'; + } + + return { + base: `${progress}%`, + change, + progress, + remainingBlocks, + timeAvg, + colorAdjustments, + colorPreviousAdjustments, + blocksInEpoch, + newDifficultyHeight, + remainingTime, + previousRetarget, + }; + }) + ); + } +} diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 25cacb428..b3cbd5fa1 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -11,7 +11,7 @@
- +
@@ -38,7 +38,7 @@
- +
@@ -228,84 +228,3 @@ - - -
Difficulty Adjustment
-
-
-
-
-
-
Remaining
-
- - {{ i }} blocks - {{ i }} block -
-
-
-
-
Estimate
-
- - - - - - - {{ epochData.change | absolute | number: '1.2-2' }} - % -
- -
-
-
- Previous: - - - - - - - - {{ epochData.previousRetarget | absolute | number: '1.2-2' }} % -
-
-
-
Current Period
-
{{ epochData.progress | number: '1.2-2' }} %
-
-
 
-
-
-
-
-
-
-
- - -
-
-
Remaining
-
-
-
-
-
-
-
Estimate
-
-
-
-
-
-
-
Current Period
-
-
-
-
-
-
-
diff --git a/frontend/src/app/dashboard/dashboard.component.scss b/frontend/src/app/dashboard/dashboard.component.scss index 541bd2129..39ca2101a 100644 --- a/frontend/src/app/dashboard/dashboard.component.scss +++ b/frontend/src/app/dashboard/dashboard.component.scss @@ -243,84 +243,6 @@ max-width: 120px; } -.difficulty-adjustment-container { - display: flex; - flex-direction: row; - justify-content: space-around; - height: 76px; - .shared-block { - color: #ffffff66; - font-size: 12px; - } - .item { - padding: 0 5px; - width: 100%; - &:nth-child(1) { - display: none; - @media (min-width: 485px) { - display: table-cell; - } - @media (min-width: 768px) { - display: none; - } - @media (min-width: 992px) { - display: table-cell; - } - } - } - .card-text { - font-size: 22px; - margin-top: -9px; - position: relative; - } -} - - -.difficulty-skeleton { - display: flex; - justify-content: space-between; - @media (min-width: 376px) { - flex-direction: row; - } - .item { - max-width: 150px; - margin: 0; - width: -webkit-fill-available; - @media (min-width: 376px) { - margin: 0 auto 0px; - } - &:first-child{ - display: none; - @media (min-width: 485px) { - display: block; - } - @media (min-width: 768px) { - display: none; - } - @media (min-width: 992px) { - display: block; - } - } - &:last-child { - margin-bottom: 0; - } - } - .card-text { - .skeleton-loader { - width: 100%; - display: block; - &:first-child { - margin: 14px auto 0; - max-width: 80px; - } - &:last-child { - margin: 10px auto 0; - max-width: 120px; - } - } - } -} - .loading-container { min-height: 76px; } diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 3dbec5ce3..a582baba3 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -15,19 +15,6 @@ interface MempoolBlocksData { size: number; } -interface EpochProgress { - base: string; - change: number; - progress: string; - remainingBlocks: number; - newDifficultyHeight: number; - colorAdjustments: string; - colorPreviousAdjustments: string; - timeAvg: string; - remainingTime: number; - previousRetarget: number; -} - interface MempoolInfoData { memPoolInfo: MempoolInfo; vBytesPerSecond: number; @@ -51,7 +38,6 @@ export class DashboardComponent implements OnInit { network$: Observable; mempoolBlocksData$: Observable; mempoolInfoData$: Observable; - difficultyEpoch$: Observable; mempoolLoadingStatus$: Observable; vBytesPerSecondLimit = 1667; blocks$: Observable; @@ -126,82 +112,6 @@ export class DashboardComponent implements OnInit { }) ); - this.difficultyEpoch$ = timer(0, 1000) - .pipe( - switchMap(() => combineLatest([ - this.stateService.blocks$.pipe(map(([block]) => block)), - this.stateService.lastDifficultyAdjustment$, - this.stateService.previousRetarget$ - ])), - map(([block, DATime, previousRetarget]) => { - const now = new Date().getTime() / 1000; - const diff = now - DATime; - const blocksInEpoch = block.height % 2016; - const progress = (blocksInEpoch >= 0) ? (blocksInEpoch / 2016 * 100).toFixed(2) : `100`; - const remainingBlocks = 2016 - blocksInEpoch; - const newDifficultyHeight = block.height + remainingBlocks; - - let change = 0; - if (remainingBlocks < 1870) { - if (blocksInEpoch > 0) { - change = (600 / (diff / blocksInEpoch ) - 1) * 100; - } - if (change > 300) { - change = 300; - } - if (change < -75) { - change = -75; - } - } - - const timeAvgDiff = change * 0.1; - - let timeAvgMins = 10; - if (timeAvgDiff > 0) { - timeAvgMins -= Math.abs(timeAvgDiff); - } else { - timeAvgMins += Math.abs(timeAvgDiff); - } - - const timeAvg = timeAvgMins.toFixed(0); - const remainingTime = (remainingBlocks * timeAvgMins * 60 * 1000) + (now * 1000); - - let colorAdjustments = '#ffffff66'; - if (change > 0) { - colorAdjustments = '#3bcc49'; - } - if (change < 0) { - colorAdjustments = '#dc3545'; - } - - let colorPreviousAdjustments = '#dc3545'; - if (previousRetarget) { - if (previousRetarget >= 0) { - colorPreviousAdjustments = '#3bcc49'; - } - if (previousRetarget === 0) { - colorPreviousAdjustments = '#ffffff66'; - } - } else { - colorPreviousAdjustments = '#ffffff66'; - } - - return { - base: `${progress}%`, - change, - progress, - remainingBlocks, - timeAvg, - colorAdjustments, - colorPreviousAdjustments, - blocksInEpoch, - newDifficultyHeight, - remainingTime, - previousRetarget, - }; - }) - ); - this.mempoolBlocksData$ = this.stateService.mempoolBlocks$ .pipe( map((mempoolBlocks) => {