From dcf78fab068181d267b9f6996e878822611d1b58 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 31 Mar 2024 03:54:11 +0000 Subject: [PATCH 1/3] Block visualization color-by-age mode --- frontend/src/app/app.constants.ts | 2 + .../block-filters.component.html | 31 ++++++--- .../block-filters.component.scss | 13 ++++ .../block-filters/block-filters.component.ts | 20 ++++-- .../block-overview-graph.component.ts | 35 +++++----- .../block-overview-graph/block-scene.ts | 4 ++ .../components/block-overview-graph/utils.ts | 65 ++++++++++++++----- .../src/app/dashboard/dashboard.component.ts | 15 +++-- frontend/src/app/services/state.service.ts | 2 +- frontend/src/app/shared/filters.utils.ts | 3 + 10 files changed, 135 insertions(+), 55 deletions(-) diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index 17105d97e..4ded1b766 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -39,6 +39,8 @@ export const mempoolFeeColors = [ 'ae005b', ]; +export const mempoolAgeColors = [ '28007d', '21017d', '1c027d', '14047d', '0d057d', '06067d', '081186', '09188c', '0b2395', '0c2a9b', '0e37a6', '0f3caa', '1045b2', '114fbb', '1254bf', '155cbf', '1965bf', '1e70be', '2076be', '2581bd', '2889bd', '2d94bc', '309dbc', '34a6bc', '39b1bb', '3cbabb', '37bbb3', '32baa9', '2bb99c', '25b993', '21b88c', '1db785', '19b67e', '14b475', '0eb36c', '08b162', '02b059', '00ae53']; + export const chartColors = [ "#D81B60", "#8E24AA", diff --git a/frontend/src/app/components/block-filters/block-filters.component.html b/frontend/src/app/components/block-filters/block-filters.component.html index 8c79cd438..093ddc11a 100644 --- a/frontend/src/app/components/block-filters/block-filters.component.html +++ b/frontend/src/app/components/block-filters/block-filters.component.html @@ -14,14 +14,29 @@
-
Match
-
- - +
+
+
Match
+
+ + +
+
+
+
Gradient
+
+ + +
+
{{ group.label }}
diff --git a/frontend/src/app/components/block-filters/block-filters.component.scss b/frontend/src/app/components/block-filters/block-filters.component.scss index 1009efd72..b1c4bce17 100644 --- a/frontend/src/app/components/block-filters/block-filters.component.scss +++ b/frontend/src/app/components/block-filters/block-filters.component.scss @@ -45,6 +45,13 @@ } .filter-menu { + .filter-row { + display: flex; + flex-direction: row; + justify-content: start; + align-items: baseline; + } + h5 { font-size: 0.8rem; color: white; @@ -118,6 +125,12 @@ background: #1a9436; } } + &.yellow { + border: solid 1px #bf7815; + &.active { + background: #bf7815; + } + } } :host-context(.block-overview-graph:hover) &, &:hover, &:active { diff --git a/frontend/src/app/components/block-filters/block-filters.component.ts b/frontend/src/app/components/block-filters/block-filters.component.ts index a16475c23..7f997617c 100644 --- a/frontend/src/app/components/block-filters/block-filters.component.ts +++ b/frontend/src/app/components/block-filters/block-filters.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Output, HostListener, Input, ChangeDetectorRef, OnChanges, SimpleChanges, OnInit, OnDestroy } from '@angular/core'; -import { ActiveFilter, FilterGroups, FilterMode, TransactionFilters } from '../../shared/filters.utils'; +import { ActiveFilter, FilterGroups, FilterMode, GradientMode, TransactionFilters } from '../../shared/filters.utils'; import { StateService } from '../../services/state.service'; import { Subscription } from 'rxjs'; @@ -22,6 +22,7 @@ export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { activeFilters: string[] = []; filterFlags: { [key: string]: boolean } = {}; filterMode: FilterMode = 'and'; + gradientMode: GradientMode = 'fee'; menuOpen: boolean = false; constructor( @@ -32,6 +33,7 @@ export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { ngOnInit(): void { this.filterSubscription = this.stateService.activeGoggles$.subscribe((active: ActiveFilter) => { this.filterMode = active.mode; + this.gradientMode = active.gradient; for (const key of Object.keys(this.filterFlags)) { this.filterFlags[key] = false; } @@ -39,7 +41,7 @@ export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { this.filterFlags[key] = !this.disabledFilters[key]; } this.activeFilters = [...active.filters.filter(key => !this.disabledFilters[key])]; - this.onFilterChanged.emit({ mode: active.mode, filters: this.activeFilters }); + this.onFilterChanged.emit({ mode: active.mode, filters: this.activeFilters, gradient: this.gradientMode }); }); } @@ -57,8 +59,14 @@ export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { setFilterMode(mode): void { this.filterMode = mode; - this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters }); - this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters] }); + this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); + this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); + } + + setGradientMode(mode): void { + this.gradientMode = mode; + this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); + this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); } toggleFilter(key): void { @@ -81,8 +89,8 @@ export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { this.activeFilters = this.activeFilters.filter(f => f != key); } const booleanFlags = this.getBooleanFlags(); - this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters }); - this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters] }); + this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); + this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); } getBooleanFlags(): bigint | null { 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 003531fce..16e482cc8 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 @@ -8,14 +8,11 @@ import { Color, Position } from './sprite-types'; import { Price } from '../../services/price.service'; import { StateService } from '../../services/state.service'; import { Subscription } from 'rxjs'; -import { defaultColorFunction, setOpacity, defaultFeeColors, defaultAuditFeeColors, defaultMarginalFeeColors, defaultAuditColors } from './utils'; +import { defaultColorFunction, setOpacity, defaultAuditColors, defaultColors } from './utils'; import { ActiveFilter, FilterMode, toFlags } from '../../shared/filters.utils'; import { detectWebGL } from '../../shared/graphs.utils'; const unmatchedOpacity = 0.2; -const unmatchedFeeColors = defaultFeeColors.map(c => setOpacity(c, unmatchedOpacity)); -const unmatchedAuditFeeColors = defaultAuditFeeColors.map(c => setOpacity(c, unmatchedOpacity)); -const unmatchedMarginalFeeColors = defaultMarginalFeeColors.map(c => setOpacity(c, unmatchedOpacity)); const unmatchedAuditColors = { censored: setOpacity(defaultAuditColors.censored, unmatchedOpacity), missing: setOpacity(defaultAuditColors.missing, unmatchedOpacity), @@ -46,6 +43,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On @Input() excludeFilters: string[] = []; @Input() filterFlags: bigint | null = null; @Input() filterMode: FilterMode = 'and'; + @Input() gradientMode: 'fee' | 'age' = 'fee'; @Input() relativeTime: number | null; @Input() blockConversion: Price; @Input() overrideColors: ((tx: TxView) => Color) | null = null; @@ -121,21 +119,22 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On this.setHighlightingEnabled(this.auditHighlighting); } if (changes.overrideColor && this.scene) { - this.scene.setColorFunction(this.overrideColors); + this.scene.setColorFunction(this.getFilterColorFunction(0n, this.gradientMode)); } - if ((changes.filterFlags || changes.showFilters || changes.filterMode)) { + if ((changes.filterFlags || changes.showFilters || changes.filterMode || changes.gradientMode)) { this.setFilterFlags(); } } setFilterFlags(goggle?: ActiveFilter): void { this.filterMode = goggle?.mode || this.filterMode; + this.gradientMode = goggle?.gradient || this.gradientMode; this.activeFilterFlags = goggle?.filters ? toFlags(goggle.filters) : this.filterFlags; if (this.scene) { if (this.activeFilterFlags != null && this.filtersAvailable) { - this.scene.setColorFunction(this.getFilterColorFunction(this.activeFilterFlags)); + this.scene.setColorFunction(this.getFilterColorFunction(this.activeFilterFlags, this.gradientMode)); } else { - this.scene.setColorFunction(this.overrideColors); + this.scene.setColorFunction(this.getFilterColorFunction(0n, this.gradientMode)); } } this.start(); @@ -212,6 +211,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On remove = remove.filter(txid => this.scene.txs[txid]); change = change.filter(tx => this.scene.txs[tx.txid]); + if (this.gradientMode === 'age') { + this.scene.updateAllColors(); + } this.scene.update(add, remove, change, direction, resetLayout); this.start(); this.updateSearchHighlight(); @@ -548,25 +550,24 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On getColorFunction(): ((tx: TxView) => Color) { if (this.filterFlags) { - return this.getFilterColorFunction(this.filterFlags); + return this.getFilterColorFunction(this.filterFlags, this.gradientMode); } else if (this.activeFilterFlags) { - return this.getFilterColorFunction(this.activeFilterFlags); + return this.getFilterColorFunction(this.activeFilterFlags, this.gradientMode); } else { - return this.overrideColors; + return this.getFilterColorFunction(0n, this.gradientMode); } } - getFilterColorFunction(flags: bigint): ((tx: TxView) => Color) { + getFilterColorFunction(flags: bigint, gradient: 'fee' | 'age'): ((tx: TxView) => Color) { return (tx: TxView) => { if ((this.filterMode === 'and' && (tx.bigintFlags & flags) === flags) || (this.filterMode === 'or' && (flags === 0n || (tx.bigintFlags & flags) > 0n))) { - return defaultColorFunction(tx); + return defaultColorFunction(tx, defaultColors[gradient], defaultAuditColors, this.relativeTime || (Date.now() / 1000)); } else { return defaultColorFunction( tx, - unmatchedFeeColors, - unmatchedAuditFeeColors, - unmatchedMarginalFeeColors, - unmatchedAuditColors + defaultColors['unmatched' + gradient], + unmatchedAuditColors, + this.relativeTime || (Date.now() / 1000) ); } }; 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 5d2196f1e..fb45e492b 100644 --- a/frontend/src/app/components/block-overview-graph/block-scene.ts +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -68,6 +68,10 @@ export default class BlockScene { setColorFunction(colorFunction: ((tx: TxView) => Color) | null): void { this.getColor = colorFunction || defaultColorFunction; + this.updateAllColors(); + } + + updateAllColors(): void { this.dirty = true; if (this.initialised && this.scene) { this.updateColors(performance.now(), 50); diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts index b6c8ccf5e..494bd7756 100644 --- a/frontend/src/app/components/block-overview-graph/utils.ts +++ b/frontend/src/app/components/block-overview-graph/utils.ts @@ -1,4 +1,4 @@ -import { feeLevels, mempoolFeeColors } from '../../app.constants'; +import { feeLevels, mempoolAgeColors, mempoolFeeColors } from '../../app.constants'; import { Color } from './sprite-types'; import TxView from './tx-view'; @@ -37,10 +37,42 @@ export function setOpacity(color: Color, opacity: number): Color { }; } +interface ColorPalette { + base: Color[], + audit: Color[], + marginal: Color[], + baseLevel: (tx: TxView, rate: number, time: number) => number, +} + // precomputed colors -export const defaultFeeColors = mempoolFeeColors.map(hexToColor); -export const defaultAuditFeeColors = defaultFeeColors.map((color) => darken(desaturate(color, 0.3), 0.9)); -export const defaultMarginalFeeColors = defaultFeeColors.map((color) => darken(desaturate(color, 0.8), 1.1)); +const defaultColors: { [key: string]: ColorPalette } = { + fee: { + base: mempoolFeeColors.map(hexToColor), + audit: [], + marginal: [], + baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 + }, + age: { + base: mempoolAgeColors.map(hexToColor), + audit: [], + marginal: [], + baseLevel: (tx: TxView, rate: number, relativeTime: number) => (!tx.time ? 0 : Math.max(0, Math.round(1.25 * Math.log2((Math.max(1, relativeTime - tx.time)))))) + }, +} +for (const key in defaultColors) { + const base = defaultColors[key].base; + defaultColors[key].audit = base.map((color) => darken(desaturate(color, 0.3), 0.9)); + defaultColors[key].marginal = base.map((color) => darken(desaturate(color, 0.8), 1.1)); + defaultColors['unmatched' + key] = { + base: defaultColors[key].base.map(c => setOpacity(c, 0.2)), + audit: defaultColors[key].audit.map(c => setOpacity(c, 0.2)), + marginal: defaultColors[key].marginal.map(c => setOpacity(c, 0.2)), + baseLevel: defaultColors[key].baseLevel, + }; +} + +export { defaultColors as defaultColors }; + export const defaultAuditColors = { censored: hexToColor('f344df'), missing: darken(desaturate(hexToColor('f344df'), 0.3), 0.7), @@ -51,22 +83,21 @@ export const defaultAuditColors = { export function defaultColorFunction( tx: TxView, - feeColors: Color[] = defaultFeeColors, - auditFeeColors: Color[] = defaultAuditFeeColors, - marginalFeeColors: Color[] = defaultMarginalFeeColors, - auditColors: { [status: string]: Color } = defaultAuditColors + colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = defaultColors.fee, + auditColors: { [status: string]: Color } = defaultAuditColors, + relativeTime?: number, ): Color { const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate - const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1; - const feeLevelColor = feeColors[feeLevelIndex] || feeColors[mempoolFeeColors.length - 1]; + const levelIndex = colors.baseLevel(tx, rate, relativeTime || (Date.now() / 1000)); + const levelColor = colors.base[levelIndex] || colors.base[mempoolFeeColors.length - 1]; // Normal mode if (!tx.scene?.highlightingEnabled) { if (tx.acc) { return auditColors.accelerated; } else { - return feeLevelColor; + return levelColor; } - return feeLevelColor; + return levelColor; } // Block audit switch(tx.status) { @@ -75,7 +106,7 @@ export function defaultColorFunction( case 'missing': case 'sigop': case 'rbf': - return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1]; + return colors.marginal[levelIndex] || colors.marginal[mempoolFeeColors.length - 1]; case 'fresh': case 'freshcpfp': return auditColors.missing; @@ -84,20 +115,20 @@ export function defaultColorFunction( case 'prioritized': return auditColors.prioritized; case 'selected': - return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1]; + return colors.marginal[levelIndex] || colors.marginal[mempoolFeeColors.length - 1]; case 'accelerated': return auditColors.accelerated; case 'found': if (tx.context === 'projected') { - return auditFeeColors[feeLevelIndex] || auditFeeColors[mempoolFeeColors.length - 1]; + return colors.audit[levelIndex] || colors.audit[mempoolFeeColors.length - 1]; } else { - return feeLevelColor; + return levelColor; } default: if (tx.acc) { return auditColors.accelerated; } else { - return feeLevelColor; + return levelColor; } } } \ No newline at end of file diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index f396ba6ae..5f0eea62d 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -7,7 +7,7 @@ import { ApiService } from '../services/api.service'; import { StateService } from '../services/state.service'; import { WebsocketService } from '../services/websocket.service'; import { SeoService } from '../services/seo.service'; -import { ActiveFilter, FilterMode, toFlags } from '../shared/filters.utils'; +import { ActiveFilter, FilterMode, GradientMode, toFlags } from '../shared/filters.utils'; import { detectWebGL } from '../shared/graphs.utils'; interface MempoolBlocksData { @@ -74,14 +74,15 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { private lastReservesBlockUpdate: number = 0; goggleResolution = 82; - goggleCycle: { index: number, name: string, mode: FilterMode, filters: string[] }[] = [ - { index: 0, name: 'All', mode: 'and', filters: [] }, - { index: 1, name: 'Consolidation', mode: 'and', filters: ['consolidation'] }, - { index: 2, name: 'Coinjoin', mode: 'and', filters: ['coinjoin'] }, - { index: 3, name: 'Data', mode: 'or', filters: ['inscription', 'fake_pubkey', 'op_return'] }, + goggleCycle: { index: number, name: string, mode: FilterMode, filters: string[], gradient: GradientMode }[] = [ + { index: 0, name: 'All', mode: 'and', filters: [], gradient: 'fee' }, + { index: 1, name: 'Consolidation', mode: 'and', filters: ['consolidation'], gradient: 'fee' }, + { index: 2, name: 'Coinjoin', mode: 'and', filters: ['coinjoin'], gradient: 'fee' }, + { index: 3, name: 'Data', mode: 'or', filters: ['inscription', 'fake_pubkey', 'op_return'], gradient: 'fee' }, ]; goggleFlags = 0n; goggleMode: FilterMode = 'and'; + gradientMode: GradientMode = 'fee'; goggleIndex = 0; private destroy$ = new Subject(); @@ -131,6 +132,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { this.goggleIndex = goggle.index; this.goggleFlags = toFlags(goggle.filters); this.goggleMode = goggle.mode; + this.gradientMode = goggle.gradient; return; } } @@ -140,6 +142,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { name: 'Custom', mode: active.mode, filters: active.filters, + gradient: active.gradient, }); this.goggleIndex = this.goggleCycle.length - 1; this.goggleFlags = toFlags(active.filters); diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 12caf9f53..4ea574c8e 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -154,7 +154,7 @@ export class StateService { searchFocus$: Subject = new Subject(); menuOpen$: BehaviorSubject = new BehaviorSubject(false); - activeGoggles$: BehaviorSubject = new BehaviorSubject({ mode: 'and', filters: [] }); + activeGoggles$: BehaviorSubject = new BehaviorSubject({ mode: 'and', filters: [], gradient: 'fee' }); constructor( @Inject(PLATFORM_ID) private platformId: any, diff --git a/frontend/src/app/shared/filters.utils.ts b/frontend/src/app/shared/filters.utils.ts index ab99e00ce..5df6c4818 100644 --- a/frontend/src/app/shared/filters.utils.ts +++ b/frontend/src/app/shared/filters.utils.ts @@ -11,9 +11,12 @@ export interface Filter { export type FilterMode = 'and' | 'or'; +export type GradientMode = 'fee' | 'age'; + export interface ActiveFilter { mode: FilterMode, filters: string[], + gradient: GradientMode, } // binary flags for transaction classification From 26227e2f3bb871d008d9471d610faed444a2970a Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 4 Apr 2024 06:56:37 +0000 Subject: [PATCH 2/3] New opacity-based age Goggles --- frontend/src/app/app.constants.ts | 2 -- .../block-overview-graph.component.ts | 8 +++--- .../components/block-overview-graph/utils.ts | 25 +++++++++++++------ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index 4ded1b766..17105d97e 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -39,8 +39,6 @@ export const mempoolFeeColors = [ 'ae005b', ]; -export const mempoolAgeColors = [ '28007d', '21017d', '1c027d', '14047d', '0d057d', '06067d', '081186', '09188c', '0b2395', '0c2a9b', '0e37a6', '0f3caa', '1045b2', '114fbb', '1254bf', '155cbf', '1965bf', '1e70be', '2076be', '2581bd', '2889bd', '2d94bc', '309dbc', '34a6bc', '39b1bb', '3cbabb', '37bbb3', '32baa9', '2bb99c', '25b993', '21b88c', '1db785', '19b67e', '14b475', '0eb36c', '08b162', '02b059', '00ae53']; - export const chartColors = [ "#D81B60", "#8E24AA", 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 16e482cc8..018a0c85a 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 @@ -8,7 +8,7 @@ import { Color, Position } from './sprite-types'; import { Price } from '../../services/price.service'; import { StateService } from '../../services/state.service'; import { Subscription } from 'rxjs'; -import { defaultColorFunction, setOpacity, defaultAuditColors, defaultColors } from './utils'; +import { defaultColorFunction, setOpacity, defaultAuditColors, defaultColors, ageColorFunction } from './utils'; import { ActiveFilter, FilterMode, toFlags } from '../../shared/filters.utils'; import { detectWebGL } from '../../shared/graphs.utils'; @@ -561,11 +561,11 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On getFilterColorFunction(flags: bigint, gradient: 'fee' | 'age'): ((tx: TxView) => Color) { return (tx: TxView) => { if ((this.filterMode === 'and' && (tx.bigintFlags & flags) === flags) || (this.filterMode === 'or' && (flags === 0n || (tx.bigintFlags & flags) > 0n))) { - return defaultColorFunction(tx, defaultColors[gradient], defaultAuditColors, this.relativeTime || (Date.now() / 1000)); + return (gradient === 'age') ? ageColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)) : defaultColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)); } else { - return defaultColorFunction( + return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : defaultColorFunction( tx, - defaultColors['unmatched' + gradient], + defaultColors.unmatchedfee, unmatchedAuditColors, this.relativeTime || (Date.now() / 1000) ); diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts index 494bd7756..568cd5ad6 100644 --- a/frontend/src/app/components/block-overview-graph/utils.ts +++ b/frontend/src/app/components/block-overview-graph/utils.ts @@ -1,4 +1,4 @@ -import { feeLevels, mempoolAgeColors, mempoolFeeColors } from '../../app.constants'; +import { feeLevels, mempoolFeeColors } from '../../app.constants'; import { Color } from './sprite-types'; import TxView from './tx-view'; @@ -52,12 +52,6 @@ const defaultColors: { [key: string]: ColorPalette } = { marginal: [], baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 }, - age: { - base: mempoolAgeColors.map(hexToColor), - audit: [], - marginal: [], - baseLevel: (tx: TxView, rate: number, relativeTime: number) => (!tx.time ? 0 : Math.max(0, Math.round(1.25 * Math.log2((Math.max(1, relativeTime - tx.time)))))) - }, } for (const key in defaultColors) { const base = defaultColors[key].base; @@ -131,4 +125,21 @@ export function defaultColorFunction( return levelColor; } } +} + +export function ageColorFunction( + tx: TxView, + colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = defaultColors.fee, + auditColors: { [status: string]: Color } = defaultAuditColors, + relativeTime?: number, +): Color { + const color = defaultColorFunction(tx, colors, auditColors, relativeTime); + + const ageLevel = (!tx.time ? 0 : (0.8 * Math.tanh((1 / 15) * Math.log2((Math.max(1, 0.6 * ((relativeTime - tx.time) - 60))))))); + return { + r: color.r, + g: color.g, + b: color.b, + a: color.a * (1 - ageLevel) + }; } \ No newline at end of file From fc5312549d2ec499a78b0e78b8f1cbc05fe5ea4e Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 4 Apr 2024 07:42:31 +0000 Subject: [PATCH 3/3] Switch gradient toggle fee -> default --- .../app/components/block-filters/block-filters.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/block-filters/block-filters.component.html b/frontend/src/app/components/block-filters/block-filters.component.html index 093ddc11a..83988d5cc 100644 --- a/frontend/src/app/components/block-filters/block-filters.component.html +++ b/frontend/src/app/components/block-filters/block-filters.component.html @@ -30,7 +30,7 @@
Gradient