Merge branch 'master' into flow-diagram-spent-connectors
This commit is contained in:
@@ -79,7 +79,7 @@ export const poolsColor = {
|
||||
'binancepool': '#1E88E5',
|
||||
'viabtc': '#039BE5',
|
||||
'btccom': '#00897B',
|
||||
'slushpool': '#00ACC1',
|
||||
'braiinspool': '#00ACC1',
|
||||
'sbicrypto': '#43A047',
|
||||
'marapool': '#7CB342',
|
||||
'luxor': '#C0CA33',
|
||||
|
||||
@@ -188,7 +188,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||
this.gl.viewport(0, 0, this.displayWidth, this.displayHeight);
|
||||
}
|
||||
if (this.scene) {
|
||||
this.scene.resize({ width: this.displayWidth, height: this.displayHeight });
|
||||
this.scene.resize({ width: this.displayWidth, height: this.displayHeight, animate: false });
|
||||
this.start();
|
||||
} else {
|
||||
this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution,
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class BlockScene {
|
||||
this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray });
|
||||
}
|
||||
|
||||
resize({ width = this.width, height = this.height }: { width?: number, height?: number}): void {
|
||||
resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.gridSize = this.width / this.gridWidth;
|
||||
@@ -38,7 +38,7 @@ export default class BlockScene {
|
||||
|
||||
this.dirty = true;
|
||||
if (this.initialised && this.scene) {
|
||||
this.updateAll(performance.now(), 50);
|
||||
this.updateAll(performance.now(), 50, 'left', animate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ export default class BlockScene {
|
||||
this.vbytesPerUnit = blockLimit / Math.pow(resolution / 1.02, 2);
|
||||
this.gridWidth = resolution;
|
||||
this.gridHeight = resolution;
|
||||
this.resize({ width, height });
|
||||
this.resize({ width, height, animate: true });
|
||||
this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight });
|
||||
|
||||
this.txs = {};
|
||||
@@ -225,14 +225,14 @@ export default class BlockScene {
|
||||
this.animateUntil = Math.max(this.animateUntil, tx.update(update));
|
||||
}
|
||||
|
||||
private updateTx(tx: TxView, startTime: number, delay: number, direction: string = 'left'): void {
|
||||
private updateTx(tx: TxView, startTime: number, delay: number, direction: string = 'left', animate: boolean = true): void {
|
||||
if (tx.dirty || this.dirty) {
|
||||
this.saveGridToScreenPosition(tx);
|
||||
this.setTxOnScreen(tx, startTime, delay, direction);
|
||||
this.setTxOnScreen(tx, startTime, delay, direction, animate);
|
||||
}
|
||||
}
|
||||
|
||||
private setTxOnScreen(tx: TxView, startTime: number, delay: number = 50, direction: string = 'left'): void {
|
||||
private setTxOnScreen(tx: TxView, startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void {
|
||||
if (!tx.initialised) {
|
||||
const txColor = tx.getColor();
|
||||
this.applyTxUpdate(tx, {
|
||||
@@ -252,30 +252,42 @@ export default class BlockScene {
|
||||
position: tx.screenPosition,
|
||||
color: txColor
|
||||
},
|
||||
duration: 1000,
|
||||
duration: animate ? 1000 : 1,
|
||||
start: startTime,
|
||||
delay,
|
||||
delay: animate ? delay : 0,
|
||||
});
|
||||
} else {
|
||||
this.applyTxUpdate(tx, {
|
||||
display: {
|
||||
position: tx.screenPosition
|
||||
},
|
||||
duration: 1000,
|
||||
minDuration: 500,
|
||||
duration: animate ? 1000 : 0,
|
||||
minDuration: animate ? 500 : 0,
|
||||
start: startTime,
|
||||
delay,
|
||||
adjust: true
|
||||
delay: animate ? delay : 0,
|
||||
adjust: animate
|
||||
});
|
||||
if (!animate) {
|
||||
this.applyTxUpdate(tx, {
|
||||
display: {
|
||||
position: tx.screenPosition
|
||||
},
|
||||
duration: 0,
|
||||
minDuration: 0,
|
||||
start: startTime,
|
||||
delay: 0,
|
||||
adjust: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateAll(startTime: number, delay: number = 50, direction: string = 'left'): void {
|
||||
private updateAll(startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void {
|
||||
this.scene.count = 0;
|
||||
const ids = this.getTxList();
|
||||
startTime = startTime || performance.now();
|
||||
for (const id of ids) {
|
||||
this.updateTx(this.txs[id], startTime, delay, direction);
|
||||
this.updateTx(this.txs[id], startTime, delay, direction, animate);
|
||||
}
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
@@ -117,8 +117,9 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
|
||||
}),
|
||||
switchMap(() => {
|
||||
let transactionObservable$: Observable<Transaction>;
|
||||
if (history.state.data && history.state.data.fee !== -1) {
|
||||
transactionObservable$ = of(history.state.data);
|
||||
const cached = this.stateService.getTxFromCache(this.txId);
|
||||
if (cached && cached.fee !== -1) {
|
||||
transactionObservable$ = of(cached);
|
||||
} else {
|
||||
transactionObservable$ = this.electrsApiService
|
||||
.getTransaction$(this.txId)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="title-block">
|
||||
<div *ngIf="rbfTransaction" class="alert alert-mempool" role="alert">
|
||||
<span i18n="transaction.rbf.replacement|RBF replacement">This transaction has been replaced by:</span>
|
||||
<a class="alert-link" [routerLink]="['/tx/' | relativeUrl, rbfTransaction.txid]" [state]="{ data: rbfTransaction.size ? rbfTransaction : null }">
|
||||
<a class="alert-link" [routerLink]="['/tx/' | relativeUrl, rbfTransaction.txid]">
|
||||
<span class="d-inline d-lg-none">{{ rbfTransaction.txid | shortenString : 24 }}</span>
|
||||
<span class="d-none d-lg-inline">{{ rbfTransaction.txid }}</span>
|
||||
</a>
|
||||
|
||||
@@ -183,8 +183,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}),
|
||||
switchMap(() => {
|
||||
let transactionObservable$: Observable<Transaction>;
|
||||
if (history.state.data && history.state.data.fee !== -1) {
|
||||
transactionObservable$ = of(history.state.data);
|
||||
const cached = this.stateService.getTxFromCache(this.txId);
|
||||
if (cached && cached.fee !== -1) {
|
||||
transactionObservable$ = of(cached);
|
||||
} else {
|
||||
transactionObservable$ = this.electrsApiService
|
||||
.getTransaction$(this.txId)
|
||||
@@ -279,6 +280,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.waitingForTransaction = false;
|
||||
}
|
||||
this.rbfTransaction = rbfTransaction;
|
||||
this.stateService.setTxCache([this.rbfTransaction]);
|
||||
});
|
||||
|
||||
this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<ng-container *ngFor="let tx of transactions; let i = index; trackBy: trackByFn">
|
||||
<div *ngIf="!transactionPage" class="header-bg box tx-page-container">
|
||||
<a class="float-left" [routerLink]="['/tx/' | relativeUrl, tx.txid]" [state]="{ data: tx }">
|
||||
<a class="float-left" [routerLink]="['/tx/' | relativeUrl, tx.txid]">
|
||||
<span style="float: left;" class="d-block d-md-none">{{ tx.txid | shortenString : 16 }}</span>
|
||||
<span style="float: left;" class="d-none d-md-block">{{ tx.txid }}</span>
|
||||
</a>
|
||||
|
||||
@@ -119,7 +119,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
this.transactionsLength = this.transactions.length;
|
||||
|
||||
this.stateService.setTxCache(this.transactions);
|
||||
|
||||
this.transactions.forEach((tx) => {
|
||||
tx['@voutLimit'] = true;
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
<div class="doc-content">
|
||||
|
||||
<div id="disclaimer">
|
||||
<table><tr><td><svg viewBox="0 0 304 304" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" style="fill:#ffc107;fill-opacity:1"><path d="M135.3 34.474c-15.62 27.306-54.206 95.63-85.21 150.534L9.075 257.583C5.382 264.08 6.76 269.217 7.908 271.7c2.326 5.028 7.29 7.537 11.155 8.215l.78.133 264.698.006-.554-.02c4.152.255 9.664-1.24 12.677-6.194 1.926-3.18 3.31-8.589-1.073-16.278L213.637 114.37l-45.351-79.205c-5.681-9.932-12.272-12.022-16.8-12.022-4.42 0-10.818 1.964-16.181 11.331h-.006zm-69.072 159.94c30.997-54.885 69.563-123.184 85.16-150.446l.186-.297c.2.303.393.582.618.981l45.363 79.22s72.377 126.47 78.569 137.283l-247.618-.007 37.719-66.734" style="fill:#ffc107;fill-opacity:1"/><path d="M152.597 247.445c8.02 0 14.518-6.728 14.518-15.025 0-8.29-6.499-15.018-14.518-15.018-8.031 0-14.529 6.728-14.529 15.018 0 8.297 6.498 15.025 14.53 15.025m-.001-147.18c11.586 0 22.23 10.958 20.977 21.7l-9.922 75.564c-.966 6.601-4.95 11.433-11.055 11.433s-10.102-4.832-11.056-11.433l-9.927-75.564c-1.26-10.742 9.39-21.7 20.983-21.7" style="fill:#ffc107;fill-opacity:1"/></g></svg></td><td><p><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="doc-item-container" *ngFor="let item of faq">
|
||||
<h3 *ngIf="item.type === 'category'">{{ item.title }}</h3>
|
||||
<div *ngIf="item.type !== 'category'" class="endpoint-container" id="{{ item.fragment }}">
|
||||
|
||||
@@ -219,6 +219,22 @@ h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#disclaimer {
|
||||
background-color: #1d1f31;
|
||||
padding: 24px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
#disclaimer svg {
|
||||
width: 50px;
|
||||
height: auto;
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
#disclaimer p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
|
||||
h3 {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<pre><code [innerText]="wrapEsModule(code)"></code></pre>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li ngbNavItem *ngIf="showCodeExample[network] && network !== 'liquid' && network !== 'liquidtestnet'" role="presentation">
|
||||
<li ngbNavItem *ngIf="code.codeTemplate.python && network !== 'liquid' && network !== 'liquidtestnet'" role="presentation">
|
||||
<a ngbNavLink (click)="adjustContainerHeight( $event )" role="tab">Python</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapEsModule(code)"></app-clipboard></div>
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
<span i18n="unknown">Unknown</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="(avgChannelDistance$ | async) as avgDistance;">
|
||||
<td i18n="lightning.avg-distance" class="text-truncate">Avg channel distance</td>
|
||||
<td>{{ avgDistance | number : '1.0-0' }} <span class="symbol">km</span> <span class="separator">/</span> {{ kmToMiles(avgDistance) | number : '1.0-0' }} <span class="symbol">mi</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -101,3 +101,7 @@ app-fiat {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ import { ActivatedRoute, ParamMap } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { SeoService } from '../../services/seo.service';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { LightningApiService } from '../lightning-api.service';
|
||||
import { GeolocationData } from '../../shared/components/geolocation/geolocation.component';
|
||||
import { ILiquidityAd, parseLiquidityAdHex } from './liquidity-ad';
|
||||
import { haversineDistance, kmToMiles } from 'src/app/shared/common.utils';
|
||||
|
||||
interface CustomRecord {
|
||||
type: string;
|
||||
@@ -34,8 +36,12 @@ export class NodeComponent implements OnInit {
|
||||
showDetails = false;
|
||||
liquidityAd: ILiquidityAd;
|
||||
tlvRecords: CustomRecord[];
|
||||
avgChannelDistance$: Observable<number | null>;
|
||||
|
||||
kmToMiles = kmToMiles;
|
||||
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
private lightningApiService: LightningApiService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private seoService: SeoService,
|
||||
@@ -119,6 +125,26 @@ export class NodeComponent implements OnInit {
|
||||
}];
|
||||
})
|
||||
);
|
||||
|
||||
this.avgChannelDistance$ = this.activatedRoute.paramMap
|
||||
.pipe(
|
||||
switchMap((params: ParamMap) => {
|
||||
return this.apiService.getChannelsGeo$(params.get('public_key'), 'nodepage');
|
||||
}),
|
||||
map((channelsGeo) => {
|
||||
if (channelsGeo?.length) {
|
||||
const totalDistance = channelsGeo.reduce((sum, chan) => {
|
||||
return sum + haversineDistance(chan[3], chan[2], chan[7], chan[6]);
|
||||
}, 0);
|
||||
return totalDistance / channelsGeo.length;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
catchError(() => {
|
||||
return null;
|
||||
})
|
||||
) as Observable<number | null>;
|
||||
}
|
||||
|
||||
toggleShowDetails(): void {
|
||||
|
||||
@@ -112,6 +112,8 @@ export class StateService {
|
||||
timeLtr: BehaviorSubject<boolean>;
|
||||
hideFlow: BehaviorSubject<boolean>;
|
||||
|
||||
txCache: { [txid: string]: Transaction } = {};
|
||||
|
||||
constructor(
|
||||
@Inject(PLATFORM_ID) private platformId: any,
|
||||
@Inject(LOCALE_ID) private locale: string,
|
||||
@@ -265,4 +267,19 @@ export class StateService {
|
||||
isLiquid() {
|
||||
return this.network === 'liquid' || this.network === 'liquidtestnet';
|
||||
}
|
||||
|
||||
setTxCache(transactions) {
|
||||
this.txCache = {};
|
||||
transactions.forEach(tx => {
|
||||
this.txCache[tx.txid] = tx;
|
||||
});
|
||||
}
|
||||
|
||||
getTxFromCache(txid) {
|
||||
if (this.txCache && this.txCache[txid]) {
|
||||
return this.txCache[txid];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,3 +118,21 @@ export function convertRegion(input, to: 'name' | 'abbreviated'): string {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function haversineDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
|
||||
const rlat1 = lat1 * Math.PI / 180;
|
||||
const rlon1 = lon1 * Math.PI / 180;
|
||||
const rlat2 = lat2 * Math.PI / 180;
|
||||
const rlon2 = lon2 * Math.PI / 180;
|
||||
|
||||
const dlat = Math.sin((rlat2 - rlat1) / 2);
|
||||
const dlon = Math.sin((rlon2 - rlon1) / 2);
|
||||
const a = Math.min(1, Math.max(0, (dlat * dlat) + (Math.cos(rlat1) * Math.cos(rlat2) * dlon * dlon)));
|
||||
const d = 2 * 6371 * Math.asin(Math.sqrt(a));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
export function kmToMiles(km: number): number {
|
||||
return km * 0.62137119;
|
||||
}
|
||||
Reference in New Issue
Block a user