Merge branch 'master' into hunicus/docs-links-alignment
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
|
||||
<div class="grid-align" [style.gridTemplateColumns]="'repeat(auto-fit, ' + resolution + 'px)'">
|
||||
<div class="graph-alignment" [class.grid-align]="!autofit" [style.gridTemplateColumns]="'repeat(auto-fit, ' + resolution + 'px)'">
|
||||
<div class="block-overview-graph">
|
||||
<canvas *browserOnly class="block-overview-canvas" [class.clickable]="!!hoverTx" #blockCanvas></canvas>
|
||||
<div class="loader-wrapper" [class.hidden]="(!isLoading || disableSpinner) && !unavailable">
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.grid-align {
|
||||
.graph-alignment {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grid-align {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, 75px);
|
||||
justify-content: center;
|
||||
|
||||
@@ -32,6 +32,7 @@ const unmatchedAuditColors = {
|
||||
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges {
|
||||
@Input() isLoading: boolean;
|
||||
@Input() resolution: number;
|
||||
@Input() autofit: boolean = false;
|
||||
@Input() blockLimit: number;
|
||||
@Input() orientation = 'left';
|
||||
@Input() flip = true;
|
||||
@@ -206,6 +207,10 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||
|
||||
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
|
||||
if (this.scene) {
|
||||
add = add.filter(tx => !this.scene.txs[tx.txid]);
|
||||
remove = remove.filter(txid => this.scene.txs[txid]);
|
||||
change = change.filter(tx => this.scene.txs[tx.txid]);
|
||||
|
||||
this.scene.update(add, remove, change, direction, resetLayout);
|
||||
this.start();
|
||||
this.updateSearchHighlight();
|
||||
|
||||
@@ -70,8 +70,9 @@
|
||||
<div class="col-sm chart-container">
|
||||
<app-block-overview-graph
|
||||
#blockGraph
|
||||
[autofit]="true"
|
||||
[isLoading]="false"
|
||||
[resolution]="80"
|
||||
[resolution]="86"
|
||||
[blockLimit]="stateService.blockVSize"
|
||||
[orientation]="'top'"
|
||||
[flip]="false"
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<div class="difficulty-stats">
|
||||
<div class="item">
|
||||
<div class="card-text bigger">
|
||||
<app-btc [satoshis]="312500000"></app-btc>
|
||||
<app-btc [satoshis]="nextSubsidy"></app-btc>
|
||||
</div>
|
||||
<div class="symbol">
|
||||
<span i18n="difficulty-box.new-subsidy">New subsidy</span>
|
||||
|
||||
@@ -62,6 +62,7 @@ export class DifficultyComponent implements OnInit {
|
||||
expectedIndex: number;
|
||||
difference: number;
|
||||
shapes: DiffShape[];
|
||||
nextSubsidy: number;
|
||||
|
||||
tooltipPosition = { x: 0, y: 0 };
|
||||
hoverSection: DiffShape | void;
|
||||
@@ -106,6 +107,7 @@ export class DifficultyComponent implements OnInit {
|
||||
const newEpochStart = Math.floor(this.stateService.latestBlockHeight / EPOCH_BLOCK_LENGTH) * EPOCH_BLOCK_LENGTH;
|
||||
const newExpectedHeight = Math.floor(newEpochStart + da.expectedBlocks);
|
||||
this.now = new Date().getTime();
|
||||
this.nextSubsidy = getNextBlockSubsidy(maxHeight);
|
||||
|
||||
if (blocksUntilHalving < da.remainingBlocks && !this.userSelectedMode) {
|
||||
this.mode = 'halving';
|
||||
@@ -233,3 +235,16 @@ export class DifficultyComponent implements OnInit {
|
||||
this.hoverSection = null;
|
||||
}
|
||||
}
|
||||
|
||||
function getNextBlockSubsidy(height: number): number {
|
||||
const halvings = Math.floor(height / 210_000) + 1;
|
||||
// Force block reward to zero when right shift is undefined.
|
||||
if (halvings >= 64) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let subsidy = BigInt(50 * 100_000_000);
|
||||
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
|
||||
subsidy >>= BigInt(halvings);
|
||||
return Number(subsidy);
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
|
||||
return;
|
||||
}
|
||||
const samples = [];
|
||||
const txs = this.transactions.filter(tx => !tx.acc).map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
|
||||
const txs = this.transactions.map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
|
||||
const maxBlockVSize = this.stateService.env.BLOCK_WEIGHT_UNITS / 4;
|
||||
const sampleInterval = maxBlockVSize / this.numSamples;
|
||||
let cumVSize = 0;
|
||||
|
||||
@@ -265,8 +265,8 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
fontSize: 11,
|
||||
formatter: (value) => {
|
||||
return this.weightMode ? value * 4 : value;
|
||||
formatter: (value): string => {
|
||||
return this.weightMode ? (value * 4).toString() : value.toString();
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
-
|
||||
<app-fee-rate [fee]="projectedBlock.feeRange[projectedBlock.feeRange.length - 1]" rounding="1.0-0" unitClass=""></app-fee-rate>
|
||||
</div>
|
||||
<div *ngIf="showMiningInfo" class="block-size">
|
||||
<div *ngIf="showMiningInfo$ | async; else noMiningInfo" class="block-size">
|
||||
<app-amount [attr.data-cy]="'mempool-block-' + i + '-total-fees'" [satoshis]="projectedBlock.totalFees" digitsInfo="1.2-3" [noFiat]="true"></app-amount>
|
||||
</div>
|
||||
<div *ngIf="!showMiningInfo" class="block-size" [innerHTML]="'‎' + (projectedBlock.blockSize | bytes: 2)"></div>
|
||||
<ng-template #noMiningInfo>
|
||||
<div class="block-size" [innerHTML]="'‎' + (projectedBlock.blockSize | bytes: 2)"></div>
|
||||
</ng-template>
|
||||
<div [attr.data-cy]="'mempool-block-' + i + '-transaction-count'" class="transaction-count">
|
||||
<ng-container *ngTemplateOutlet="projectedBlock.nTx === 1 ? transactionsSingular : transactionsPlural; context: {$implicit: projectedBlock.nTx | number}"></ng-container>
|
||||
<ng-template #transactionsSingular let-i i18n="shared.transaction-count.singular">{{ i }} transaction</ng-template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
|
||||
import { Subscription, Observable, of, combineLatest } from 'rxjs';
|
||||
import { Subscription, Observable, of, combineLatest, BehaviorSubject } from 'rxjs';
|
||||
import { MempoolBlock } from '../../interfaces/websocket.interface';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { Router } from '@angular/router';
|
||||
@@ -42,6 +42,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
mempoolBlocks$: Observable<MempoolBlock[]>;
|
||||
difficultyAdjustments$: Observable<DifficultyAdjustment>;
|
||||
loadingBlocks$: Observable<boolean>;
|
||||
showMiningInfo$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
blocksSubscription: Subscription;
|
||||
|
||||
mempoolBlocksFull: MempoolBlock[] = [];
|
||||
@@ -57,10 +58,8 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
network = '';
|
||||
now = new Date().getTime();
|
||||
timeOffset = 0;
|
||||
showMiningInfo = false;
|
||||
timeLtrSubscription: Subscription;
|
||||
timeLtr: boolean;
|
||||
showMiningInfoSubscription: Subscription;
|
||||
animateEntry: boolean = false;
|
||||
|
||||
blockOffset: number = 155;
|
||||
@@ -98,10 +97,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.widthChange.emit(this.mempoolWidth);
|
||||
|
||||
if (['', 'testnet', 'signet'].includes(this.stateService.network)) {
|
||||
this.showMiningInfoSubscription = this.stateService.showMiningInfo$.subscribe((showMiningInfo) => {
|
||||
this.showMiningInfo = showMiningInfo;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
this.showMiningInfo$ = this.stateService.showMiningInfo$;
|
||||
}
|
||||
|
||||
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||
@@ -267,7 +263,6 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.chainTipSubscription.unsubscribe();
|
||||
this.keySubscription.unsubscribe();
|
||||
this.isTabHiddenSubscription.unsubscribe();
|
||||
this.showMiningInfoSubscription.unsubscribe();
|
||||
clearTimeout(this.resetTransitionTimeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -411,7 +411,6 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
||||
padding: [20, 0, 0, 0],
|
||||
},
|
||||
type: 'time',
|
||||
boundaryGap: false,
|
||||
axisLine: { onZero: true },
|
||||
axisLabel: {
|
||||
margin: 20,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<span class="menu-click text-nowrap ellipsis">
|
||||
<strong>
|
||||
<span *ngIf="user.username.includes('@'); else usernamenospace">{{ user.username }}</span>
|
||||
<ng-template #usernamenospace>@{{ user.username }}</ng-template>
|
||||
<ng-template #usernamenospace>@{{ user.username }}</ng-template>
|
||||
</strong>
|
||||
</span>
|
||||
<span class="badge mr-1 badge-og" *ngIf="user.ogRank">
|
||||
|
||||
@@ -24,7 +24,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy {
|
||||
timeLtrSubscription: Subscription;
|
||||
timeLtr: boolean = this.stateService.timeLtr.value;
|
||||
chainTipSubscription: Subscription;
|
||||
chainTip: number = 100;
|
||||
chainTip: number = -1;
|
||||
tipIsSet: boolean = false;
|
||||
lastMark: MarkBlockState;
|
||||
markBlockSubscription: Subscription;
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
|
||||
<br>
|
||||
|
||||
<p>If you have any questions about this Policy, would like to speak with us about the use of our Marks in ways not described in the Policy, or see any abuse of our Marks, please email us at <legal@mempool.space></p>
|
||||
<p>If you have any questions about this Policy, would like to speak with us about the use of our Marks in ways not described in the Policy, or see any abuse of our Marks, please email us at <legal@mempool.space></p>
|
||||
|
||||
</ol>
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, NgZone, OnInit } from '@angular/core';
|
||||
import { SeoService } from '../../services/seo.service';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { delay, Observable, switchMap, tap, zip } from 'rxjs';
|
||||
import { delay, Observable, of, switchMap, tap, zip } from 'rxjs';
|
||||
import { AssetsService } from '../../services/assets.service';
|
||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
|
||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { EChartsOption, echarts } from '../../graphs/echarts';
|
||||
import { isMobile } from '../../shared/common.utils';
|
||||
import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe';
|
||||
import { getFlagEmoji } from '../../shared/common.utils';
|
||||
import { lerpColor } from '../../shared/graphs.utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nodes-channels-map',
|
||||
@@ -50,6 +53,7 @@ export class NodesChannelsMap implements OnInit {
|
||||
private router: Router,
|
||||
private zone: NgZone,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private amountShortenerPipe: AmountShortenerPipe,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -86,10 +90,12 @@ export class NodesChannelsMap implements OnInit {
|
||||
return zip(
|
||||
this.assetsService.getWorldMapJson$,
|
||||
this.style !== 'channelpage' ? this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined, this.style) : [''],
|
||||
[params.get('public_key') ?? undefined]
|
||||
[params.get('public_key') ?? undefined],
|
||||
this.style === 'widget' ? of(undefined) : this.apiService.getWorldNodes$(),
|
||||
).pipe(tap((data) => {
|
||||
echarts.registerMap('world', data[0]);
|
||||
|
||||
let maxLiquidity = data[3]?.maxLiquidity;
|
||||
const channelsLoc = [];
|
||||
const nodes = [];
|
||||
const nodesPubkeys = {};
|
||||
@@ -197,13 +203,24 @@ export class NodesChannelsMap implements OnInit {
|
||||
this.zoom = -0.05 * distance + 8;
|
||||
}
|
||||
|
||||
this.prepareChartOptions(nodes, channelsLoc);
|
||||
if (data[3]) {
|
||||
for (const node of nodes) {
|
||||
const foundNode = data[3].nodes.find((n) => n[2] === node[3]);
|
||||
if (foundNode) {
|
||||
node.push(foundNode[4], foundNode[5], foundNode[6]?.en, foundNode[7]);
|
||||
maxLiquidity = Math.max(maxLiquidity ?? 0, foundNode[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maxLiquidity = Math.max(1, maxLiquidity);
|
||||
this.prepareChartOptions(nodes, channelsLoc, maxLiquidity);
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
prepareChartOptions(nodes, channels) {
|
||||
prepareChartOptions(nodes, channels, maxLiquidity) {
|
||||
let title: object;
|
||||
if (channels.length === 0) {
|
||||
if (!this.placeholder) {
|
||||
@@ -267,7 +284,12 @@ export class NodesChannelsMap implements OnInit {
|
||||
data: nodes,
|
||||
coordinateSystem: 'geo',
|
||||
geoIndex: 0,
|
||||
symbolSize: this.nodeSize,
|
||||
symbolSize: (params) => {
|
||||
if (maxLiquidity) {
|
||||
return 10 * Math.pow(params[5] / maxLiquidity, 0.2) + 3;
|
||||
}
|
||||
return this.nodeSize;
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
backgroundColor: 'rgba(17, 19, 31, 1)',
|
||||
@@ -281,11 +303,25 @@ export class NodesChannelsMap implements OnInit {
|
||||
formatter: (value) => {
|
||||
const data = value.data;
|
||||
const alias = data[4].length > 0 ? data[4] : data[3].slice(0, 20);
|
||||
return `<b style="color: white">${alias}</b>`;
|
||||
}
|
||||
const liquidity = data[5] >= 100000000 ?
|
||||
`${this.amountShortenerPipe.transform(data[5] / 100000000)} BTC` :
|
||||
`${this.amountShortenerPipe.transform(data[5], 2)} sats`;
|
||||
|
||||
return `
|
||||
<b style="color: white">${alias}</b><br>
|
||||
${liquidity}<br>` +
|
||||
$localize`:@@205c1b86ac1cc419c4d0cca51fdde418c4ffdc20:${data[6]}:INTERPOLATION: channels` + `<br>
|
||||
${getFlagEmoji(data[8])} ${data[7]}
|
||||
`;
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: 'white',
|
||||
color: (params) => {
|
||||
if (!maxLiquidity) {
|
||||
return 'white';
|
||||
}
|
||||
return `${lerpColor('#1E88E5', '#D81B60', Math.pow(params.data[5] / maxLiquidity, 0.2))}`;
|
||||
},
|
||||
opacity: 1,
|
||||
borderColor: 'black',
|
||||
borderWidth: 0,
|
||||
@@ -361,8 +397,6 @@ export class NodesChannelsMap implements OnInit {
|
||||
}
|
||||
|
||||
chartOptions.series[0].itemStyle.borderWidth = nodeBorder;
|
||||
chartOptions.series[0].symbolSize += e.zoom > 1 ? speed * 15 : -speed * 15;
|
||||
chartOptions.series[0].symbolSize = Math.max(4, Math.min(7, chartOptions.series[0].symbolSize));
|
||||
|
||||
chartOptions.series[1].lineStyle.opacity += e.zoom > 1 ? speed : -speed;
|
||||
chartOptions.series[1].lineStyle.width += e.zoom > 1 ? speed : -speed;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
|
||||
import { Inject, Injectable, PLATFORM_ID, makeStateKey, TransferState } from '@angular/core';
|
||||
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
import { TransferState, makeStateKey } from '@angular/platform-browser';
|
||||
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -7,5 +7,5 @@ if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
export { AppServerModule } from './app/app.server.module';
|
||||
export { AppServerModule } from './app/app.module.server';
|
||||
export { renderModule } from '@angular/platform-server';
|
||||
|
||||
Reference in New Issue
Block a user