mirror of
https://github.com/mempool/mempool.git
synced 2025-03-15 04:11:48 +01:00
Merge pull request #5453 from mempool/mononaut/acceleration-sparkles
acceleration sparkles
This commit is contained in:
commit
5f6af83944
6 changed files with 139 additions and 2 deletions
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="sparkles" #sparkleAnchor>
|
||||||
|
<div *ngFor="let sparkle of sparkles" class="sparkle" [style]="sparkle.style">
|
||||||
|
<span class="inner-sparkle" [style]="sparkle.rotation">+</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,45 @@
|
||||||
|
.sparkles {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--block-size);
|
||||||
|
height: 50px;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sparkle {
|
||||||
|
position: absolute;
|
||||||
|
color: rgba(152, 88, 255, 0.75);
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8) rotate(0deg);
|
||||||
|
animation: pop ease 2000ms forwards, sparkle ease 500ms infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-sparkle {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.8) rotate(0deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: scale(1) rotate(72deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(0) rotate(360deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sparkle {
|
||||||
|
0% {
|
||||||
|
color: rgba(152, 88, 255, 0.75);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
color: rgba(198, 162, 255, 0.75);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: rgba(152, 88, 255, 0.75);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-acceleration-sparkles',
|
||||||
|
templateUrl: './acceleration-sparkles.component.html',
|
||||||
|
styleUrls: ['./acceleration-sparkles.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class AccelerationSparklesComponent implements OnChanges {
|
||||||
|
@Input() arrow: ElementRef<HTMLDivElement>;
|
||||||
|
@Input() run: boolean = false;
|
||||||
|
|
||||||
|
@ViewChild('sparkleAnchor')
|
||||||
|
sparkleAnchor: ElementRef<HTMLDivElement>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private cd: ChangeDetectorRef,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
endTimeout: any;
|
||||||
|
lastSparkle: number = 0;
|
||||||
|
sparkleWidth: number = 0;
|
||||||
|
sparkles: any[] = [];
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
if (changes.run) {
|
||||||
|
if (this.endTimeout) {
|
||||||
|
clearTimeout(this.endTimeout);
|
||||||
|
this.endTimeout = null;
|
||||||
|
}
|
||||||
|
if (this.run) {
|
||||||
|
this.doSparkle();
|
||||||
|
} else {
|
||||||
|
this.endTimeout = setTimeout(() => {
|
||||||
|
this.sparkles = [];
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doSparkle(): void {
|
||||||
|
if (this.run) {
|
||||||
|
const now = performance.now();
|
||||||
|
if (now - this.lastSparkle > 20) {
|
||||||
|
this.lastSparkle = now;
|
||||||
|
if (this.arrow?.nativeElement && this.sparkleAnchor?.nativeElement) {
|
||||||
|
const anchor = this.sparkleAnchor.nativeElement.getBoundingClientRect().right;
|
||||||
|
const right = this.arrow.nativeElement.getBoundingClientRect().right;
|
||||||
|
const dx = (anchor - right) + 30;
|
||||||
|
const numSparkles = Math.ceil(Math.random() * 3);
|
||||||
|
for (let i = 0; i < numSparkles; i++) {
|
||||||
|
this.sparkles.push({
|
||||||
|
style: {
|
||||||
|
right: (dx + (Math.random() * 10)) + 'px',
|
||||||
|
top: (15 + (Math.random() * 30)) + 'px',
|
||||||
|
},
|
||||||
|
rotation: {
|
||||||
|
transform: `rotate(${Math.random() * 360}deg)`,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while (this.sparkles.length > 200) {
|
||||||
|
this.sparkles.shift();
|
||||||
|
}
|
||||||
|
this.cd.markForCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.doSparkle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,8 @@
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="arrowVisible" id="arrow-up" [ngStyle]="{'right': rightPosition + (blockWidth * 0.3) + containerOffset + 'px', transition: transition }" [class.blink]="txPosition?.accelerated"></div>
|
<app-acceleration-sparkles [style]="{ position: 'absolute', right: 0}" [arrow]="arrowElement" [run]="acceleratingArrow"></app-acceleration-sparkles>
|
||||||
|
<div *ngIf="arrowVisible" #arrowUp id="arrow-up" [ngStyle]="{'right': rightPosition + (blockWidth * 0.3) + containerOffset + 'px', transition: transition }" [class.blink]="txPosition?.accelerated"></div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core';
|
||||||
import { Subscription, Observable, of, combineLatest } from 'rxjs';
|
import { Subscription, Observable, of, combineLatest } from 'rxjs';
|
||||||
import { MempoolBlock } from '../../interfaces/websocket.interface';
|
import { MempoolBlock } from '../../interfaces/websocket.interface';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
|
@ -77,6 +77,9 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
maxArrowPosition = 0;
|
maxArrowPosition = 0;
|
||||||
rightPosition = 0;
|
rightPosition = 0;
|
||||||
transition = 'background 2s, right 2s, transform 1s';
|
transition = 'background 2s, right 2s, transform 1s';
|
||||||
|
@ViewChild('arrowUp')
|
||||||
|
arrowElement: ElementRef<HTMLDivElement>;
|
||||||
|
acceleratingArrow: boolean = false;
|
||||||
|
|
||||||
markIndex: number;
|
markIndex: number;
|
||||||
txPosition: MempoolPosition;
|
txPosition: MempoolPosition;
|
||||||
|
@ -201,6 +204,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
this.markBlocksSubscription = this.stateService.markBlock$
|
this.markBlocksSubscription = this.stateService.markBlock$
|
||||||
.subscribe((state) => {
|
.subscribe((state) => {
|
||||||
|
const oldTxPosition = this.txPosition;
|
||||||
this.markIndex = undefined;
|
this.markIndex = undefined;
|
||||||
this.txPosition = undefined;
|
this.txPosition = undefined;
|
||||||
this.txFeePerVSize = undefined;
|
this.txFeePerVSize = undefined;
|
||||||
|
@ -209,6 +213,12 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
if (state.mempoolPosition) {
|
if (state.mempoolPosition) {
|
||||||
this.txPosition = state.mempoolPosition;
|
this.txPosition = state.mempoolPosition;
|
||||||
|
if (this.txPosition.accelerated && !oldTxPosition.accelerated) {
|
||||||
|
this.acceleratingArrow = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.acceleratingArrow = false;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (state.txFeePerVSize) {
|
if (state.txFeePerVSize) {
|
||||||
this.txFeePerVSize = state.txFeePerVSize;
|
this.txFeePerVSize = state.txFeePerVSize;
|
||||||
|
|
|
@ -100,6 +100,7 @@ import { MempoolErrorComponent } from './components/mempool-error/mempool-error.
|
||||||
import { AccelerationsListComponent } from '../components/acceleration/accelerations-list/accelerations-list.component';
|
import { AccelerationsListComponent } from '../components/acceleration/accelerations-list/accelerations-list.component';
|
||||||
import { PendingStatsComponent } from '../components/acceleration/pending-stats/pending-stats.component';
|
import { PendingStatsComponent } from '../components/acceleration/pending-stats/pending-stats.component';
|
||||||
import { AccelerationStatsComponent } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
|
import { AccelerationStatsComponent } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
|
||||||
|
import { AccelerationSparklesComponent } from '../components/acceleration/sparkles/acceleration-sparkles.component';
|
||||||
|
|
||||||
import { BlockViewComponent } from '../components/block-view/block-view.component';
|
import { BlockViewComponent } from '../components/block-view/block-view.component';
|
||||||
import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component';
|
import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component';
|
||||||
|
@ -225,6 +226,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
||||||
AccelerationsListComponent,
|
AccelerationsListComponent,
|
||||||
AccelerationStatsComponent,
|
AccelerationStatsComponent,
|
||||||
PendingStatsComponent,
|
PendingStatsComponent,
|
||||||
|
AccelerationSparklesComponent,
|
||||||
HttpErrorComponent,
|
HttpErrorComponent,
|
||||||
TwitterWidgetComponent,
|
TwitterWidgetComponent,
|
||||||
FaucetComponent,
|
FaucetComponent,
|
||||||
|
@ -355,6 +357,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
||||||
AccelerationsListComponent,
|
AccelerationsListComponent,
|
||||||
AccelerationStatsComponent,
|
AccelerationStatsComponent,
|
||||||
PendingStatsComponent,
|
PendingStatsComponent,
|
||||||
|
AccelerationSparklesComponent,
|
||||||
HttpErrorComponent,
|
HttpErrorComponent,
|
||||||
TwitterWidgetComponent,
|
TwitterWidgetComponent,
|
||||||
TwitterLogin,
|
TwitterLogin,
|
||||||
|
|
Loading…
Add table
Reference in a new issue