From be5fcf01c8d721a5e09017112922509bfae3367f Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 29 Sep 2022 22:37:49 +0000 Subject: [PATCH 1/5] Reversible block arrows & key navigation --- .../app/components/block/block.component.html | 44 +++++++------------ .../app/components/block/block.component.scss | 18 +++++++- .../app/components/block/block.component.ts | 17 +++++-- .../mempool-blocks.component.ts | 13 +++++- frontend/src/app/services/state.service.ts | 8 ++++ frontend/src/app/shared/shared.module.ts | 3 +- 6 files changed, 67 insertions(+), 36 deletions(-) diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index d21cea34e..a44abe3a0 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -1,36 +1,24 @@
-
+

- Genesis - - - - - {{ blockHeight }} - - - + Block + Genesis + + + + - - Block - - - - - - - - - {{ blockHeight }} - - - - - - + {{ blockHeight }} + + + - +

diff --git a/frontend/src/app/components/block/block.component.scss b/frontend/src/app/components/block/block.component.scss index f047cbcfa..1a43013ae 100644 --- a/frontend/src/app/components/block/block.component.scss +++ b/frontend/src/app/components/block/block.component.scss @@ -111,7 +111,8 @@ h1 { .next-previous-blocks { font-size: 28px; - display: inline-block; + display: inline-flex; + flex-direction: row; @media (min-width: 768px) { font-size: 36px; } @@ -125,6 +126,21 @@ h1 { } } +.time-ltr .next-previous-blocks { + .nav-arrow { + transform: rotate(180deg); + } + .nav-arrow.next { + order: 2; + } + .block-link { + order: 1; + } + .nav-arrow.prev { + order: 0; + } +} + .disable { font-size: 28px; color: #393e5c73; diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index ac6d9b21e..2e6a73c62 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -57,6 +57,8 @@ export class BlockComponent implements OnInit, OnDestroy { nextBlockSubscription: Subscription = undefined; nextBlockSummarySubscription: Subscription = undefined; nextBlockTxListSubscription: Subscription = undefined; + timeLtrSubscription: Subscription; + timeLtr: boolean; @ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent; @@ -80,6 +82,10 @@ export class BlockComponent implements OnInit, OnDestroy { this.network = this.stateService.network; this.itemsPerPage = this.stateService.env.ITEMS_PER_PAGE; + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + }); + this.txsLoadingStatus$ = this.route.paramMap .pipe( switchMap(() => this.stateService.loadingIndicators$), @@ -277,10 +283,12 @@ export class BlockComponent implements OnInit, OnDestroy { }); this.keyNavigationSubscription = this.stateService.keyNavigation$.subscribe((event) => { - if (this.showPreviousBlocklink && event.key === 'ArrowRight' && this.nextBlockHeight - 2 >= 0) { + const prevKey = this.timeLtr ? 'ArrowLeft' : 'ArrowRight'; + const nextKey = this.timeLtr ? 'ArrowRight' : 'ArrowLeft'; + if (this.showPreviousBlocklink && event.key === prevKey && this.nextBlockHeight - 2 >= 0) { this.navigateToPreviousBlock(); } - if (event.key === 'ArrowLeft') { + if (event.key === nextKey) { if (this.showNextBlocklink) { this.navigateToNextBlock(); } else { @@ -298,6 +306,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.blocksSubscription.unsubscribe(); this.networkChangedSubscription.unsubscribe(); this.queryParamsSubscription.unsubscribe(); + this.timeLtrSubscription.unsubscribe(); this.unsubscribeNextBlockSubscriptions(); } @@ -392,8 +401,8 @@ export class BlockComponent implements OnInit, OnDestroy { } setNextAndPreviousBlockLink(){ - if (this.latestBlock && this.blockHeight) { - if (this.blockHeight === 0){ + if (this.latestBlock) { + if (!this.blockHeight){ this.showPreviousBlocklink = false; } else { this.showPreviousBlocklink = true; diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 4202330b0..77313302f 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -36,6 +36,8 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { now = new Date().getTime(); timeOffset = 0; showMiningInfo = false; + timeLtrSubscription: Subscription; + timeLtr: boolean; blockWidth = 125; blockPadding = 30; @@ -72,6 +74,10 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url)); } + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + }); + if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { this.feeRounding = '1.0-1'; } @@ -160,8 +166,10 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { if (this.markIndex === undefined) { return; } + const prevKey = this.timeLtr ? 'ArrowLeft' : 'ArrowRight'; + const nextKey = this.timeLtr ? 'ArrowRight' : 'ArrowLeft'; - if (event.key === 'ArrowRight') { + if (event.key === prevKey) { if (this.mempoolBlocks[this.markIndex - 1]) { this.router.navigate([this.relativeUrlPipe.transform('mempool-block/'), this.markIndex - 1]); } else { @@ -173,7 +181,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { } }); } - } else if (event.key === 'ArrowLeft') { + } else if (event.key === nextKey) { if (this.mempoolBlocks[this.markIndex + 1]) { this.router.navigate([this.relativeUrlPipe.transform('/mempool-block/'), this.markIndex + 1]); } @@ -185,6 +193,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.markBlocksSubscription.unsubscribe(); this.blockSubscription.unsubscribe(); this.networkSubscription.unsubscribe(); + this.timeLtrSubscription.unsubscribe(); clearTimeout(this.resetTransitionTimeout); } diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index b0e018941..920f32dd9 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -6,6 +6,7 @@ import { BlockExtended, DifficultyAdjustment, OptimizedMempoolStats } from '../i import { Router, NavigationStart } from '@angular/router'; import { isPlatformBrowser } from '@angular/common'; import { map, shareReplay } from 'rxjs/operators'; +import { StorageService } from './storage.service'; interface MarkBlockState { blockHeight?: number; @@ -108,10 +109,12 @@ export class StateService { keyNavigation$ = new Subject(); blockScrolling$: Subject = new Subject(); + timeLtr: BehaviorSubject; constructor( @Inject(PLATFORM_ID) private platformId: any, private router: Router, + private storageService: StorageService, ) { const browserWindow = window || {}; // @ts-ignore @@ -147,6 +150,11 @@ export class StateService { } this.blockVSize = this.env.BLOCK_WEIGHT_UNITS / 4; + + this.timeLtr = new BehaviorSubject(this.storageService.getValue('time-preference-ltr') === 'true'); + this.timeLtr.subscribe((ltr) => { + this.storageService.setValue('time-preference-ltr', ltr ? 'true' : 'false'); + }); } setNetworkBasedonUrl(url: string) { diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index c4973d75c..dd06269d2 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -4,7 +4,7 @@ import { NgbCollapse, NgbCollapseModule, NgbRadioGroup, NgbTypeaheadModule } fro import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle, faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, - faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft } from '@fortawesome/free-solid-svg-icons'; + faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate } from '@fortawesome/free-solid-svg-icons'; import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { MasterPageComponent } from '../components/master-page/master-page.component'; import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component'; @@ -291,6 +291,7 @@ export class SharedModule { library.addIcons(faFileAlt); library.addIcons(faRedoAlt); library.addIcons(faArrowAltCircleRight); + library.addIcons(faArrowsRotate); library.addIcons(faExternalLinkAlt); library.addIcons(faSortUp); library.addIcons(faCaretUp); From 7ddb5ef9af34d9bd575a7fe56d4c05c54f6a6f50 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 29 Sep 2022 22:40:46 +0000 Subject: [PATCH 2/5] Reversible mempool block visualization --- .../block-overview-graph.component.ts | 12 ++++++-- .../block-overview-graph/block-scene.ts | 18 ++++++++++++ .../mempool-block-overview.component.html | 2 +- .../mempool-block-overview.component.ts | 29 ++++++++++++++----- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts index f4980b088..14607f398 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -1,4 +1,4 @@ -import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy } from '@angular/core'; +import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy, OnChanges } from '@angular/core'; import { TransactionStripped } from '../../interfaces/websocket.interface'; import { FastVertexArray } from './fast-vertex-array'; import BlockScene from './block-scene'; @@ -11,7 +11,7 @@ import { Position } from './sprite-types'; templateUrl: './block-overview-graph.component.html', styleUrls: ['./block-overview-graph.component.scss'], }) -export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy { +export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges { @Input() isLoading: boolean; @Input() resolution: number; @Input() blockLimit: number; @@ -57,6 +57,14 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy { this.resizeCanvas(); } + ngOnChanges(changes): void { + if (changes.orientation || changes.flip) { + if (this.scene) { + this.scene.setOrientation(this.orientation, this.flip); + } + } + } + ngOnDestroy(): void { if (this.animationFrameRequest) { cancelAnimationFrame(this.animationFrameRequest); diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts index 20a219e75..af0ba56fa 100644 --- a/frontend/src/app/components/block-overview-graph/block-scene.ts +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -42,6 +42,24 @@ export default class BlockScene { } } + setOrientation(orientation: string, flip: boolean): void { + this.orientation = orientation; + this.flip = flip; + this.dirty = true; + const startTime = performance.now(); + Object.values(this.txs).forEach(txView => { + this.saveGridToScreenPosition(txView); + this.applyTxUpdate(txView, { + display: { + position: txView.screenPosition, + color: txView.getColor() + }, + duration: 0 + }); + this.setTxOnScreen(txView, startTime, 0); + }); + } + // Destroy the current layout and clean up graphics sprites without any exit animation destroy(): void { Object.values(this.txs).forEach(tx => tx.destroy()); diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html index 304b2a7f9..3cb4ff3e8 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html @@ -3,7 +3,7 @@ [isLoading]="isLoading$ | async" [resolution]="75" [blockLimit]="stateService.blockVSize" - [orientation]="'left'" + [orientation]="timeLtr ? 'right' : 'left'" [flip]="true" (txClickEvent)="onTxClick($event)" > diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts index b7fb65753..7a39e3536 100644 --- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts +++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts @@ -1,5 +1,5 @@ import { Component, ComponentRef, ViewChild, HostListener, Input, Output, EventEmitter, - OnDestroy, OnChanges, ChangeDetectionStrategy, AfterViewInit } from '@angular/core'; + OnInit, OnDestroy, OnChanges, ChangeDetectionStrategy, ChangeDetectorRef, AfterViewInit } from '@angular/core'; import { StateService } from '../../services/state.service'; import { MempoolBlockDelta, TransactionStripped } from '../../interfaces/websocket.interface'; import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; @@ -14,7 +14,7 @@ import { Router } from '@angular/router'; templateUrl: './mempool-block-overview.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, AfterViewInit { +export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit { @Input() index: number; @Output() txPreviewEvent = new EventEmitter(); @@ -23,6 +23,10 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte lastBlockHeight: number; blockIndex: number; isLoading$ = new BehaviorSubject(true); + timeLtrSubscription: Subscription; + timeLtr: boolean; + chainDirection: string = 'right'; + poolDirection: string = 'left'; blockSub: Subscription; deltaSub: Subscription; @@ -31,8 +35,18 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte public stateService: StateService, private websocketService: WebsocketService, private router: Router, + private cd: ChangeDetectorRef, ) { } + ngOnInit(): void { + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + this.chainDirection = ltr ? 'left' : 'right'; + this.poolDirection = ltr ? 'right' : 'left'; + this.cd.markForCheck(); + }); + } + ngAfterViewInit(): void { this.blockSub = merge( of(true), @@ -50,7 +64,7 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte ngOnChanges(changes): void { if (changes.index) { if (this.blockGraph) { - this.blockGraph.clear(changes.index.currentValue > changes.index.previousValue ? 'right' : 'left'); + this.blockGraph.clear(changes.index.currentValue > changes.index.previousValue ? this.chainDirection : this.poolDirection); } this.isLoading$.next(true); this.websocketService.startTrackMempoolBlock(changes.index.currentValue); @@ -60,16 +74,17 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte ngOnDestroy(): void { this.blockSub.unsubscribe(); this.deltaSub.unsubscribe(); + this.timeLtrSubscription.unsubscribe(); this.websocketService.stopTrackMempoolBlock(); } replaceBlock(transactionsStripped: TransactionStripped[]): void { const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight); if (this.blockIndex !== this.index) { - const direction = (this.blockIndex == null || this.index < this.blockIndex) ? 'left' : 'right'; + const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection; this.blockGraph.enter(transactionsStripped, direction); } else { - this.blockGraph.replace(transactionsStripped, blockMined ? 'right' : 'left'); + this.blockGraph.replace(transactionsStripped, blockMined ? this.chainDirection : this.poolDirection); } this.lastBlockHeight = this.stateService.latestBlockHeight; @@ -81,10 +96,10 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight); if (this.blockIndex !== this.index) { - const direction = (this.blockIndex == null || this.index < this.blockIndex) ? 'left' : 'right'; + const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection; this.blockGraph.replace(delta.added, direction); } else { - this.blockGraph.update(delta.added, delta.removed, blockMined ? 'right' : 'left', blockMined); + this.blockGraph.update(delta.added, delta.removed, blockMined ? this.chainDirection : this.poolDirection, blockMined); } this.lastBlockHeight = this.stateService.latestBlockHeight; From 3023be257c0383470dde553c3c9a2de158757d7b Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 29 Sep 2022 22:45:40 +0000 Subject: [PATCH 3/5] Reversible blockchain components --- .../blockchain-blocks.component.html | 4 +- .../blockchain-blocks.component.scss | 9 ++- .../blockchain-blocks.component.ts | 8 +++ .../blockchain/blockchain.component.html | 14 ++-- .../blockchain/blockchain.component.scss | 70 ++++++++++++++++--- .../blockchain/blockchain.component.ts | 20 +++++- .../mempool-blocks.component.html | 4 +- .../mempool-blocks.component.scss | 21 +++++- .../mempool-blocks.component.ts | 5 +- 9 files changed, 130 insertions(+), 25 deletions(-) diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index f1d2cca6d..6bd617435 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -1,4 +1,4 @@ -
+
-
+
diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index 8c108dff7..6b8430e2a 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -22,7 +22,7 @@ .mined-block { position: absolute; top: 0px; - transition: 2s; + transition: background 2s, left 2s, transform 1s; } .block-size { @@ -34,6 +34,7 @@ position: absolute; top: 0px; left: 40px; + transition: left 2s; } .block-body { @@ -145,3 +146,9 @@ opacity: 0; pointer-events : none; } + +.time-ltr { + .bitcoin-block { + transform: scaleX(-1); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 621d3b4b6..8ac925eaf 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -33,6 +33,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { blocksFilled = false; transition = '1s'; showMiningInfo = false; + timeLtrSubscription: Subscription; + timeLtr: boolean; gradientColors = { '': ['#9339f4', '#105fb0'], @@ -61,6 +63,11 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url)); } + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + this.cd.markForCheck(); + }); + if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { this.feeRounding = '1.0-1'; } @@ -123,6 +130,7 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { this.networkSubscription.unsubscribe(); this.tabHiddenSubscription.unsubscribe(); this.markBlockSubscription.unsubscribe(); + this.timeLtrSubscription.unsubscribe(); clearInterval(this.interval); } diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index c49d08c5a..241f60c8a 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,9 +1,13 @@ -
-
+
+
- - -
+
+ + +
+
+ +
diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index 990cf9535..1e229e330 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -16,7 +16,7 @@ .blockchain-wrapper { height: 250px; - -webkit-user-select: none; /* Safari */ + -webkit-user-select: none; /* Safari */ -moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+/Edge */ user-select: none; /* Standard */ @@ -24,23 +24,46 @@ .position-container { position: absolute; - left: 50%; + left: 0; top: 75px; + transform: translateX(50vw); + transition: transform 1s; } .position-container.liquid, .position-container.liquidtestnet { - left: 420px; + transform: translateX(420px); +} + +@media (min-width: 768px) { + .blockchain-wrapper.time-ltr { + .position-container.liquid, .position-container.liquidtestnet { + transform: translateX(calc(100vw - 420px)); + } + } } @media (max-width: 767.98px) { - .position-container { - left: 95%; + .blockchain-wrapper { + .position-container { + transform: translateX(95vw); + } + .position-container.liquid, .position-container.liquidtestnet { + transform: translateX(50vw); + } + .position-container.loading { + transform: translateX(50vw); + } } - .position-container.liquid, .position-container.liquidtestnet { - left: 50%; - } - .position-container.loading { - left: 50%; + .blockchain-wrapper.time-ltr { + .position-container { + transform: translateX(5vw); + } + .position-container.liquid, .position-container.liquidtestnet { + transform: translateX(50vw); + } + .position-container.loading { + transform: translateX(50vw); + } } } @@ -57,4 +80,31 @@ width: 300px; left: -150px; top: 0px; +} + +.time-toggle { + color: white; + font-size: 1rem; + position: absolute; + bottom: -1.5em; + left: 1px; + transform: translateX(-50%); + background: none; + border: none; + outline: none; + margin: 0; + padding: 0; + transition: transform 1s; +} + +.blockchain-wrapper.ltr-transition .blocks-wrapper { + transition: transform 1s; +} + +.blockchain-wrapper.time-ltr .blocks-wrapper { + transform: scaleX(-1); +} + +.blockchain-wrapper.time-ltr .time-toggle { + transform: translateX(-50%) scaleX(-1); } \ No newline at end of file diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index b8ae8d1d2..e99b3532d 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core'; +import { Subscription } from 'rxjs'; import { StateService } from '../../services/state.service'; @Component({ @@ -7,8 +8,11 @@ import { StateService } from '../../services/state.service'; styleUrls: ['./blockchain.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class BlockchainComponent implements OnInit { +export class BlockchainComponent implements OnInit, OnDestroy { network: string; + timeLtrSubscription: Subscription; + timeLtr: boolean = this.stateService.timeLtr.value; + ltrTransitionEnabled = false; constructor( public stateService: StateService, @@ -16,5 +20,17 @@ export class BlockchainComponent implements OnInit { ngOnInit() { this.network = this.stateService.network; + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + }); + } + + ngOnDestroy() { + this.timeLtrSubscription.unsubscribe(); + } + + toggleTimeDirection() { + this.ltrTransitionEnabled = true; + this.stateService.timeLtr.next(!this.timeLtr); } } diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 77ca95b2f..9e70c6e74 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -1,5 +1,5 @@ -
+
@@ -45,7 +45,7 @@ -
+
diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss index c41cde3fc..8032be92f 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss @@ -1,7 +1,7 @@ .bitcoin-block { width: 125px; height: 125px; - transition: 2s; + transition: background 2s, right 2s, transform 1s; } .block-size { @@ -33,6 +33,7 @@ .block-body { text-align: center; + transition: transform 1s; } @keyframes opacityPulse { @@ -73,6 +74,7 @@ background-color: #232838; transform:skew(40deg); transform-origin:top; + transition: transform 1s, left 1s; } .bitcoin-block::before { @@ -83,9 +85,11 @@ top: -12px; left: -20px; background-color: #191c27; + z-index: -1; transform: skewY(50deg); transform-origin: top; + transition: transform 1s, left 1s; } .mempool-block.bitcoin-block::after { @@ -128,3 +132,18 @@ .blockLink:hover { text-decoration: none; } + +.time-ltr { + .bitcoin-block::after { + transform: skew(-40deg); + left: 20px; + } + + .bitcoin-block::before { + transform: skewY(-50deg); + left: 125px; + } + .block-body { + transform: scaleX(-1); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 77313302f..17236e2ca 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -46,7 +46,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { feeRounding = '1.0-0'; rightPosition = 0; - transition = '2s'; + transition = 'background 2s, right 2s, transform 1s'; markIndex: number; txFeePerVSize: number; @@ -76,6 +76,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { this.timeLtr = !!ltr; + this.cd.markForCheck(); }); if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { @@ -278,7 +279,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.arrowVisible = true; this.resetTransitionTimeout = window.setTimeout(() => { - this.transition = '2s'; + this.transition = 'background 2s, right 2s, transform 1s'; this.cd.markForCheck(); }, 100); return; From aeb29a489a82194ce22a79fcefd6290b755a9fdd Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 30 Sep 2022 00:42:02 +0000 Subject: [PATCH 4/5] Animate mempool block viz reversal --- .../block-overview-graph/block-scene.ts | 15 +++------------ .../src/app/components/block/block.component.scss | 2 +- .../blockchain-blocks.component.scss | 1 - .../blockchain/blockchain.component.scss | 4 ++-- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts index af0ba56fa..39ac44e7a 100644 --- a/frontend/src/app/components/block-overview-graph/block-scene.ts +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -46,18 +46,9 @@ export default class BlockScene { this.orientation = orientation; this.flip = flip; this.dirty = true; - const startTime = performance.now(); - Object.values(this.txs).forEach(txView => { - this.saveGridToScreenPosition(txView); - this.applyTxUpdate(txView, { - display: { - position: txView.screenPosition, - color: txView.getColor() - }, - duration: 0 - }); - this.setTxOnScreen(txView, startTime, 0); - }); + if (this.initialised && this.scene) { + this.updateAll(performance.now(), 50); + } } // Destroy the current layout and clean up graphics sprites without any exit animation diff --git a/frontend/src/app/components/block/block.component.scss b/frontend/src/app/components/block/block.component.scss index 1a43013ae..d6c4d65b4 100644 --- a/frontend/src/app/components/block/block.component.scss +++ b/frontend/src/app/components/block/block.component.scss @@ -128,7 +128,7 @@ h1 { .time-ltr .next-previous-blocks { .nav-arrow { - transform: rotate(180deg); + transform: scaleX(-1); } .nav-arrow.next { order: 2; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index 6b8430e2a..adde4a945 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -34,7 +34,6 @@ position: absolute; top: 0px; left: 40px; - transition: left 2s; } .block-body { diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index 1e229e330..2f13374fe 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -94,10 +94,10 @@ outline: none; margin: 0; padding: 0; - transition: transform 1s; } -.blockchain-wrapper.ltr-transition .blocks-wrapper { +.blockchain-wrapper.ltr-transition .blocks-wrapper, +.blockchain-wrapper.ltr-transition .time-toggle { transition: transform 1s; } From 2884e3ef8206870b868dbd2f1725c623d1369514 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 30 Sep 2022 02:01:59 +0000 Subject: [PATCH 5/5] Fix liquid block divider position --- .../src/app/components/blockchain/blockchain.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 241f60c8a..5127c8c74 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,5 +1,5 @@
-
+