diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 73b010b91..64dc1d5ba 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -81,6 +81,7 @@ class Blocks { private async $getTransactionsExtended( blockHash: string, blockHeight: number, + blockTime: number, onlyCoinbase: boolean, txIds: string[] | null = null, quiet: boolean = false, @@ -101,6 +102,12 @@ class Blocks { if (!onlyCoinbase) { for (const txid of txIds) { if (mempool[txid]) { + mempool[txid].status = { + confirmed: true, + block_height: blockHeight, + block_hash: blockHash, + block_time: blockTime, + }; transactionMap[txid] = mempool[txid]; foundInMempool++; totalFound++; @@ -608,7 +615,7 @@ class Blocks { } const blockHash = await bitcoinApi.$getBlockHash(blockHeight); const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash); - const transactions = await this.$getTransactionsExtended(blockHash, block.height, true, null, true); + const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true, null, true); const blockExtended = await this.$getBlockExtended(block, transactions); newlyIndexed++; @@ -701,7 +708,7 @@ class Blocks { const verboseBlock = await bitcoinClient.getBlock(blockHash, 2); const block = BitcoinApi.convertBlock(verboseBlock); const txIds: string[] = verboseBlock.tx.map(tx => tx.txid); - const transactions = await this.$getTransactionsExtended(blockHash, block.height, false, txIds, false, true) as MempoolTransactionExtended[]; + const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, false, txIds, false, true) as MempoolTransactionExtended[]; // fill in missing transaction fee data from verboseBlock for (let i = 0; i < transactions.length; i++) { @@ -890,7 +897,7 @@ class Blocks { const blockHash = await bitcoinApi.$getBlockHash(height); const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash); - const transactions = await this.$getTransactionsExtended(blockHash, block.height, true); + const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true); const blockExtended = await this.$getBlockExtended(block, transactions); if (Common.indexingEnabled()) { @@ -902,7 +909,7 @@ class Blocks { public async $indexStaleBlock(hash: string): Promise { const block: IEsploraApi.Block = await bitcoinApi.$getBlock(hash); - const transactions = await this.$getTransactionsExtended(hash, block.height, true); + const transactions = await this.$getTransactionsExtended(hash, block.height, block.timestamp, true); const blockExtended = await this.$getBlockExtended(block, transactions); blockExtended.canonical = await bitcoinApi.$getBlockHash(block.height); diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts index 1b68a5a99..667ad1e28 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts @@ -63,7 +63,8 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On return; } this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference'); - this.MA = this.calculateMA(this.data.series[0]); + const windowSize = Math.max(10, Math.floor(this.data.series[0].length / 8)); + this.MA = this.calculateMA(this.data.series[0], windowSize); this.mountChart(); } @@ -74,33 +75,22 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On this.isLoading = false; } - /// calculate the moving average of maData - calculateMA(maData): number[][] { + /// calculate the moving average of the provided data based on windowSize + calculateMA(data: number[][], windowSize: number = 100): number[][] { //update const variables that are not changed const ma: number[][] = []; let sum = 0; let i = 0; - const len = maData.length; - - //Adjust window length based on the length of the data - //5% appeared as a good amount from tests - //TODO: make this a text box in the UI - const maWindowLen = Math.ceil(len * 0.05); - - //calculate the center of the moving average window - const center = Math.floor(maWindowLen / 2); //calculate the centered moving average - for (i = center; i < len - center; i++) { - sum = 0; - //build out ma as we loop through the data - ma[i] = []; - ma[i].push(maData[i][0]); - for (let j = i - center; j <= i + center; j++) { - sum += maData[j][1]; + for (i = 0; i < data.length; i++) { + sum += data[i][1]; + if (i >= windowSize) { + sum -= data[i - windowSize][1]; + const midpoint = i - Math.floor(windowSize / 2); + const avg = sum / windowSize; + ma.push([data[midpoint][0], avg]); } - - ma[i].push(sum / maWindowLen); } //return the moving average array @@ -138,36 +128,22 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On } }], } - }, - { - zlevel: 0, - name: 'MA', - data: this.MA, - type: 'line', - smooth: false, - showSymbol: false, - symbol: 'none', - lineStyle: { - width: 1, - color: "white", - }, - markLine: { - silent: true, + }); + if (this.template !== 'widget') { + seriesGraph.push({ + zlevel: 0, + name: 'MA', + data: this.MA, + type: 'line', + smooth: false, + showSymbol: false, symbol: 'none', lineStyle: { - color: '#fff', - opacity: 1, width: 2, - }, - data: [{ - yAxis: 1667, - label: { - show: false, - color: '#ffffff', - } - }], - } - }); + color: "white", + } + }); + } this.mempoolStatsChartOption = { grid: { diff --git a/frontend/src/app/graphs/echarts.ts b/frontend/src/app/graphs/echarts.ts index 588e5e5f1..342867168 100644 --- a/frontend/src/app/graphs/echarts.ts +++ b/frontend/src/app/graphs/echarts.ts @@ -1,7 +1,7 @@ // Import tree-shakeable echarts import * as echarts from 'echarts/core'; import { LineChart, LinesChart, BarChart, TreemapChart, PieChart, ScatterChart } from 'echarts/charts'; -import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, DataZoomComponent, VisualMapComponent } from 'echarts/components'; +import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, DataZoomComponent, VisualMapComponent, MarkLineComponent } from 'echarts/components'; import { SVGRenderer, CanvasRenderer } from 'echarts/renderers'; // Typescript interfaces import { EChartsOption, TreemapSeriesOption, LineSeriesOption, PieSeriesOption } from 'echarts'; @@ -11,7 +11,7 @@ echarts.use([ SVGRenderer, CanvasRenderer, TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, DataZoomComponent, - VisualMapComponent, + VisualMapComponent, MarkLineComponent, LineChart, LinesChart, BarChart, TreemapChart, PieChart, ScatterChart ]); export { echarts, EChartsOption, TreemapSeriesOption, LineSeriesOption, PieSeriesOption }; \ No newline at end of file