Merge branch 'master' into natsoni/contrast-theme

This commit is contained in:
natsoni
2024-04-08 14:54:38 +09:00
79 changed files with 17384 additions and 6148 deletions

View File

@@ -9,14 +9,11 @@ import { Price } from '../../services/price.service';
import { StateService } from '../../services/state.service';
import { ThemeService } from 'src/app/services/theme.service';
import { Subscription } from 'rxjs';
import { defaultColorFunction, setOpacity, defaultFeeColors, defaultAuditFeeColors, defaultMarginalFeeColors, defaultAuditColors, contrastFeeColors, contrastAuditFeeColors, contrastMarginalFeeColors, contrastAuditColors, contrastColorFunction } from './utils';
import { defaultColorFunction, setOpacity, defaultFeeColors, defaultAuditFeeColors, defaultMarginalFeeColors, defaultAuditColors } 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),
@@ -57,6 +54,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;
@@ -137,21 +135,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();
@@ -229,6 +228,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();
@@ -564,32 +566,27 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
}
getColorFunction(): ((tx: TxView) => Color) {
if (this.filterFlags) {
return this.getFilterColorFunction(this.filterFlags);
} else if (this.activeFilterFlags) {
return this.getFilterColorFunction(this.activeFilterFlags);
} else {
if (this.overrideColors) {
return this.overrideColors;
} else if (this.filterFlags) {
return this.getFilterColorFunction(this.filterFlags, this.gradientMode);
} else if (this.activeFilterFlags) {
return this.getFilterColorFunction(this.activeFilterFlags, this.gradientMode);
} else {
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 this.themeService.theme !== 'default' ? contrastColorFunction(tx) : defaultColorFunction(tx);
return defaultColorFunction(tx);
} else {
return this.themeService.theme !== 'default' ? contrastColorFunction(
return defaultColorFunction(
tx,
unmatchedContrastFeeColors,
unmatchedContrastAuditFeeColors,
unmatchedContrastMarginalFeeColors,
unmatchedContrastAuditColors
) : defaultColorFunction(
tx,
unmatchedFeeColors,
unmatchedAuditFeeColors,
unmatchedMarginalFeeColors,
unmatchedAuditColors
defaultColors.unmatchedfee,
unmatchedAuditColors,
this.relativeTime || (Date.now() / 1000)
);
}
};

View File

@@ -69,7 +69,7 @@ export default class BlockScene {
}
setColorFunction(colorFunction: ((tx: TxView) => Color) | null): void {
this.theme.theme !== 'default' ? this.getColor = colorFunction || contrastColorFunction : this.getColor = colorFunction || defaultColorFunction;
this.getColor = colorFunction || defaultColorFunction;
this.dirty = true;
if (this.initialised && this.scene) {
this.updateColors(performance.now(), 50);

View File

@@ -37,8 +37,15 @@ 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 = defaultMempoolFeeColors.map(hexToColor);
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));
export const defaultAuditColors = {
@@ -62,22 +69,21 @@ export const contrastAuditColors = {
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[defaultMempoolFeeColors.length - 1];
const feeLevelColor = feeColors[feeLevelIndex] || feeColors[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) {
@@ -86,7 +92,7 @@ export function defaultColorFunction(
case 'missing':
case 'sigop':
case 'rbf':
return marginalFeeColors[feeLevelIndex] || marginalFeeColors[defaultMempoolFeeColors.length - 1];
return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
case 'fresh':
case 'freshcpfp':
return auditColors.missing;
@@ -95,24 +101,45 @@ export function defaultColorFunction(
case 'prioritized':
return auditColors.prioritized;
case 'selected':
return marginalFeeColors[feeLevelIndex] || marginalFeeColors[defaultMempoolFeeColors.length - 1];
return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
case 'accelerated':
return auditColors.accelerated;
case 'found':
if (tx.context === 'projected') {
return auditFeeColors[feeLevelIndex] || auditFeeColors[defaultMempoolFeeColors.length - 1];
return auditFeeColors[feeLevelIndex] || auditFeeColors[mempoolFeeColors.length - 1];
} else {
return feeLevelColor;
return levelColor;
}
default:
if (tx.acc) {
return auditColors.accelerated;
} else {
return feeLevelColor;
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 {
if (tx.acc || tx.status === 'accelerated') {
return auditColors.accelerated;
}
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)
};
}
export function contrastColorFunction(
tx: TxView,
feeColors: Color[] = contrastFeeColors,