Add mempool special block animation.
This commit is contained in:
		
							parent
							
								
									46a2854f67
								
							
						
					
					
						commit
						a3de75ebf4
					
				@ -130,12 +130,11 @@ export const languages: Language[] = [
 | 
			
		||||
   { code: 'zh', name: '中文' },            // Chinese
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const specialBlocks = {
 | 
			
		||||
  '708998': {
 | 
			
		||||
    labelEvent: '🌱 Taproot Activated!',
 | 
			
		||||
  '709632': {
 | 
			
		||||
    labelEvent: '🌱 Taproot activated!',
 | 
			
		||||
  },
 | 
			
		||||
  '840000': {
 | 
			
		||||
    labelEvent: '🥳 Halving Event!',
 | 
			
		||||
    labelEvent: '🥳 Halving',
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -120,33 +120,3 @@
 | 
			
		||||
  50% {opacity: 1.0;}
 | 
			
		||||
  100% {opacity: 0.7;}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Blinking block
 | 
			
		||||
@keyframes shadowyBackground {
 | 
			
		||||
  0% {
 | 
			
		||||
    box-shadow: -10px -15px 75px rgba(#5E35B1, 1);
 | 
			
		||||
    transform: rotate(0deg) translateY(0px);
 | 
			
		||||
  }
 | 
			
		||||
  25% {
 | 
			
		||||
    transform: rotate(3deg) translateY(5px);
 | 
			
		||||
  }
 | 
			
		||||
  50% {
 | 
			
		||||
    box-shadow: -10px -15px 75px rgba(#5E35B1, .3);
 | 
			
		||||
    transform: rotate(0deg) translateY(0px);
 | 
			
		||||
  }
 | 
			
		||||
  75% {
 | 
			
		||||
    transform: rotate(-3deg) translateY(5px);
 | 
			
		||||
  }
 | 
			
		||||
  100% {
 | 
			
		||||
    box-shadow: -10px -15px 75px rgba(#5E35B1, 1);
 | 
			
		||||
    transform: rotate(0deg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blink-bg {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background: repeating-linear-gradient(rgb(45, 51, 72), rgb(45, 51, 72) 0.163525%, rgb(16, 95, 176) 100%, rgb(147, 57, 244) 0.163525%) !important;
 | 
			
		||||
  animation: shadowyBackground 1s infinite;
 | 
			
		||||
  box-shadow: -10px -15px 75px rgba(#5E35B1, 1);
 | 
			
		||||
  transition: 100ms all ease-in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
<ng-container *ngIf="(loadingBlocks$ | async) === false; else loadingBlocks">
 | 
			
		||||
  <div class="mempool-blocks-container" *ngIf="(timeAvg$ | async) as timeAvg;">
 | 
			
		||||
    <div class="flashing">      
 | 
			
		||||
    <div class="flashing">
 | 
			
		||||
      <ng-template ngFor let-projectedBlock [ngForOf]="mempoolBlocks$ | async" let-i="index" [ngForTrackBy]="trackByFn">
 | 
			
		||||
        <div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]">
 | 
			
		||||
        <div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]"  [class.blink-bg]="projectedBlock.blink">
 | 
			
		||||
          <a [routerLink]="['/mempool-block/' | relativeUrl, i]" class="blockLink"> </a>
 | 
			
		||||
          <div class="block-body">
 | 
			
		||||
            <div class="fees">
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@
 | 
			
		||||
 | 
			
		||||
.flashing {
 | 
			
		||||
  animation: opacityPulse 2s ease-out;
 | 
			
		||||
  animation-iteration-count: infinite; 
 | 
			
		||||
  animation-iteration-count: infinite;
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bitcoin-block::after {
 | 
			
		||||
  content: '';   
 | 
			
		||||
  content: '';
 | 
			
		||||
  width: 125px;
 | 
			
		||||
  height: 24px;
 | 
			
		||||
  position:absolute;
 | 
			
		||||
@ -68,7 +68,7 @@
 | 
			
		||||
  left: -20px;
 | 
			
		||||
  background-color: #232838;
 | 
			
		||||
  transform:skew(40deg);
 | 
			
		||||
  transform-origin:top;    
 | 
			
		||||
  transform-origin:top;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bitcoin-block::before {
 | 
			
		||||
@ -78,18 +78,18 @@
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: -12px;
 | 
			
		||||
  left: -20px;
 | 
			
		||||
  background-color: #191c27; 
 | 
			
		||||
  
 | 
			
		||||
  background-color: #191c27;
 | 
			
		||||
 | 
			
		||||
  transform: skewY(50deg);
 | 
			
		||||
  transform-origin: top;     
 | 
			
		||||
  transform-origin: top;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mempool-block.bitcoin-block::after {
 | 
			
		||||
  background-color: #403834; 
 | 
			
		||||
  background-color: #403834;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mempool-block.bitcoin-block::before {
 | 
			
		||||
  background-color: #2d2825; 
 | 
			
		||||
  background-color: #2d2825;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.black-background {
 | 
			
		||||
@ -102,8 +102,8 @@
 | 
			
		||||
  position: relative;
 | 
			
		||||
  right: 75px;
 | 
			
		||||
  top: 140px;
 | 
			
		||||
  width: 0; 
 | 
			
		||||
  height: 0; 
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  border-left: 35px solid transparent;
 | 
			
		||||
  border-right: 35px solid transparent;
 | 
			
		||||
  border-bottom: 35px solid #FFF;
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,8 @@ import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { take, map, switchMap, share } from 'rxjs/operators';
 | 
			
		||||
import { feeLevels, mempoolFeeColors } from 'src/app/app.constants';
 | 
			
		||||
import { specialBlocks } from 'src/app/app.constants';
 | 
			
		||||
import { Block } from 'src/app/interfaces/electrs.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-mempool-blocks',
 | 
			
		||||
@ -13,12 +15,13 @@ import { feeLevels, mempoolFeeColors } from 'src/app/app.constants';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  specialBlocks = specialBlocks;
 | 
			
		||||
  mempoolBlocks: MempoolBlock[] = [];
 | 
			
		||||
  mempoolEmptyBlocks: MempoolBlock[] = this.mountEmptyBlocks();
 | 
			
		||||
  mempoolBlocks$: Observable<MempoolBlock[]>;
 | 
			
		||||
  timeAvg$: Observable<number>;
 | 
			
		||||
  loadingBlocks$: Observable<boolean>;
 | 
			
		||||
  blocksSubscription: Subscription;
 | 
			
		||||
 | 
			
		||||
  mempoolBlocksFull: MempoolBlock[] = [];
 | 
			
		||||
  mempoolBlockStyles = [];
 | 
			
		||||
@ -74,26 +77,25 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
      fromEvent(window, 'resize')
 | 
			
		||||
    )
 | 
			
		||||
    .pipe(
 | 
			
		||||
      switchMap(() => this.stateService.mempoolBlocks$),
 | 
			
		||||
      map((blocks) => {
 | 
			
		||||
        if (!blocks.length) {
 | 
			
		||||
          return [{ index: 0, blockSize: 0, blockVSize: 0, feeRange: [0, 0], medianFee: 0, nTx: 0, totalFees: 0 }];
 | 
			
		||||
        }
 | 
			
		||||
        return blocks;
 | 
			
		||||
      }),
 | 
			
		||||
      map((blocks) => {
 | 
			
		||||
        blocks.forEach((block, i) => {
 | 
			
		||||
          block.index = this.blockIndex + i;
 | 
			
		||||
        });
 | 
			
		||||
        const stringifiedBlocks = JSON.stringify(blocks);
 | 
			
		||||
        this.mempoolBlocksFull = JSON.parse(stringifiedBlocks);
 | 
			
		||||
        this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(stringifiedBlocks));
 | 
			
		||||
        this.updateMempoolBlockStyles();
 | 
			
		||||
        this.calculateTransactionPosition();
 | 
			
		||||
        return this.mempoolBlocks;
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
        switchMap(() => combineLatest([
 | 
			
		||||
          this.stateService.blocks$.pipe(map(([block]) => block)),
 | 
			
		||||
          this.stateService.mempoolBlocks$
 | 
			
		||||
        ])),
 | 
			
		||||
        map(([lastBlock, mempoolBlocks]) => {
 | 
			
		||||
          mempoolBlocks.forEach((block, i) => {
 | 
			
		||||
            block.index = this.blockIndex + i;
 | 
			
		||||
            block.height = lastBlock.height + i + 1;
 | 
			
		||||
            block.blink = specialBlocks[block.height] ? true : false;
 | 
			
		||||
          });
 | 
			
		||||
          const stringifiedBlocks = JSON.stringify(mempoolBlocks);
 | 
			
		||||
          this.mempoolBlocksFull = JSON.parse(stringifiedBlocks);
 | 
			
		||||
          this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(stringifiedBlocks));
 | 
			
		||||
          this.updateMempoolBlockStyles();
 | 
			
		||||
          this.calculateTransactionPosition();
 | 
			
		||||
 | 
			
		||||
          return this.mempoolBlocks;
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    this.timeAvg$ = timer(0, 1000)
 | 
			
		||||
      .pipe(
 | 
			
		||||
@ -118,7 +120,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
          } else {
 | 
			
		||||
            timeAvgMins += Math.abs(timeAvgDiff);
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          return timeAvgMins * 60 * 1000;
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,8 @@ export interface WebsocketResponse {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MempoolBlock {
 | 
			
		||||
  blink?: boolean;
 | 
			
		||||
  height?: number;
 | 
			
		||||
  blockSize: number;
 | 
			
		||||
  blockVSize: number;
 | 
			
		||||
  nTx: number;
 | 
			
		||||
 | 
			
		||||
@ -941,3 +941,35 @@ th {
 | 
			
		||||
    width: 220px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Blinking block
 | 
			
		||||
@keyframes shadowyBackground {
 | 
			
		||||
  0% {
 | 
			
		||||
    box-shadow: -10px -15px 75px rgba(#5E35B1, 1);
 | 
			
		||||
    transform: rotate(0deg) translateY(0px);
 | 
			
		||||
  }
 | 
			
		||||
  25% {
 | 
			
		||||
    transform: rotate(3deg) translateY(5px);
 | 
			
		||||
  }
 | 
			
		||||
  50% {
 | 
			
		||||
    box-shadow: -10px -15px 75px rgba(#5E35B1, .3);
 | 
			
		||||
    transform: rotate(0deg) translateY(0px);
 | 
			
		||||
  }
 | 
			
		||||
  75% {
 | 
			
		||||
    transform: rotate(-3deg) translateY(5px);
 | 
			
		||||
  }
 | 
			
		||||
  100% {
 | 
			
		||||
    box-shadow: -10px -15px 75px rgba(#5E35B1, 1);
 | 
			
		||||
    transform: rotate(0deg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blink-bg {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background: repeating-linear-gradient(rgb(45, 51, 72), rgb(45, 51, 72) 0.163525%, rgb(16, 95, 176) 100%, rgb(147, 57, 244) 0.163525%) !important;
 | 
			
		||||
  animation: shadowyBackground 1s infinite;
 | 
			
		||||
  box-shadow: -10px -15px 75px rgba(#5E35B1, 1);
 | 
			
		||||
  transition: 100ms all ease-in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user