diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts index f051e9d51..94ab9b686 100644 --- a/frontend/src/app/components/block-overview-graph/utils.ts +++ b/frontend/src/app/components/block-overview-graph/utils.ts @@ -12,7 +12,7 @@ export function hexToColor(hex: string): Color { } export function colorToHex(color: Color): string { - return [color.r, color.g, color.b].map(c => Math.round(c * 255).toString(16)).join(''); + return [color.r, color.g, color.b].map(c => Math.max(0, Math.min(Math.round(c * 255), 255)).toString(16)).join(''); } export function desaturate(color: Color, amount: number): Color { @@ -35,6 +35,8 @@ export function darken(color: Color, amount: number): Color { } export function mix(color1: Color, color2: Color, amount: number): Color { + // clamp to 0-1 + amount = Math.max(0, Math.min(amount, 1)); return { r: color1.r * (1 - amount) + color2.r * amount, g: color1.g * (1 - amount) + color2.g * amount, diff --git a/frontend/src/app/components/utxo-graph/utxo-graph.component.ts b/frontend/src/app/components/utxo-graph/utxo-graph.component.ts index b712fcf87..ebcad891c 100644 --- a/frontend/src/app/components/utxo-graph/utxo-graph.component.ts +++ b/frontend/src/app/components/utxo-graph/utxo-graph.component.ts @@ -8,9 +8,12 @@ import { RelativeUrlPipe } from '@app/shared/pipes/relative-url/relative-url.pip import { renderSats } from '@app/shared/common.utils'; import { colorToHex, hexToColor, mix } from '@components/block-overview-graph/utils'; import { TimeService } from '@app/services/time.service'; +import { WebsocketService } from '@app/services/websocket.service'; +import { Acceleration } from '@interfaces/node-api.interface'; +import { defaultAuditColors } from '@components/block-overview-graph/utils'; -const newColorHex = '1bd8f4'; -const oldColorHex = '9339f4'; +const newColorHex = '1BF4AF'; +const oldColorHex = '3C39F4'; const pendingColorHex = 'eba814'; const newColor = hexToColor(newColorHex); const oldColor = hexToColor(oldColorHex); @@ -61,8 +64,10 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { @Input() widget: boolean = false; subscription: Subscription; + accelerationsSubscription: Subscription; lastUpdate: number = 0; updateInterval; + accelerationMap: Record = {}; chartOptions: EChartsOption = {}; chartInitOptions = { @@ -80,6 +85,7 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { private router: Router, private relativeUrlPipe: RelativeUrlPipe, private timeService: TimeService, + private websocketService: WebsocketService, ) { // re-render the chart every 10 seconds, to keep the age colors up to date this.updateInterval = setInterval(() => { @@ -87,6 +93,18 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { this.prepareChartOptions(this.utxos); } }, 10000); + + this.websocketService.startTrackAccelerations(); + this.accelerationsSubscription = this.stateService.liveAccelerations$.subscribe((accelerations) => { + this.accelerationMap = accelerations.reduce((acc, acceleration) => { + acc[acceleration.txid] = acceleration; + return acc; + }, {}); + + this.applyAccelerations(); + this.prepareChartOptions(this.utxos); + }); + } ngOnChanges(changes: SimpleChanges): void { @@ -95,10 +113,20 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { return; } if (changes.utxos) { + this.applyAccelerations(); this.prepareChartOptions(this.utxos); } } + applyAccelerations(): void { + for (const utxo of this.utxos) { + delete utxo.status['accelerated']; + if (this.accelerationMap[utxo.txid]) { + utxo.status['accelerated'] = true; + } + } + } + prepareChartOptions(utxos: Utxo[]): void { if (!utxos || utxos.length === 0) { return; @@ -311,7 +339,12 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy {
${valueStr}
- ${utxo.status.confirmed ? 'Confirmed ' + this.timeService.calculate(utxo.status.block_time, 'since', true, 1, 'minute').text : 'Pending'} + ${utxo.status.confirmed + ? 'Confirmed ' + this.timeService.calculate(utxo.status.block_time, 'since', true, 1, 'minute').text + : utxo.status['accelerated'] + ? 'Accelerated' + : 'Pending' + } `; }, } @@ -322,7 +355,9 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { } getColor(utxo: Utxo): string { - if (utxo.status.confirmed) { + if (utxo.status['accelerated']) { + return colorToHex(defaultAuditColors.accelerated); + } else if (utxo.status.confirmed) { const age = Date.now() / 1000 - utxo.status.block_time; const oneHour = 60 * 60; const fourYears = 4 * 365 * 24 * 60 * 60; @@ -366,6 +401,8 @@ export class UtxoGraphComponent implements OnChanges, OnDestroy { this.subscription.unsubscribe(); } clearInterval(this.updateInterval); + this.websocketService.stopTrackAccelerations(); + this.accelerationsSubscription.unsubscribe(); } isMobile(): boolean {