Merge hashrate and difficulty into one chart
This commit is contained in:
parent
98e0e1e9c1
commit
83a382a0cb
@ -42,9 +42,7 @@ class Mining {
|
|||||||
});
|
});
|
||||||
|
|
||||||
poolsStatistics['pools'] = poolsStats;
|
poolsStatistics['pools'] = poolsStats;
|
||||||
|
poolsStatistics['oldestIndexedBlockTimestamp'] = await BlocksRepository.$oldestBlockTimestamp();
|
||||||
const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
|
|
||||||
poolsStatistics['oldestIndexedBlockTimestamp'] = oldestBlock.getTime();
|
|
||||||
|
|
||||||
const blockCount: number = await BlocksRepository.$blockCount(null, interval);
|
const blockCount: number = await BlocksRepository.$blockCount(null, interval);
|
||||||
poolsStatistics['blockCount'] = blockCount;
|
poolsStatistics['blockCount'] = blockCount;
|
||||||
@ -79,26 +77,14 @@ class Mining {
|
|||||||
* Return the historical difficulty adjustments and oldest indexed block timestamp
|
* Return the historical difficulty adjustments and oldest indexed block timestamp
|
||||||
*/
|
*/
|
||||||
public async $getHistoricalDifficulty(interval: string | null): Promise<object> {
|
public async $getHistoricalDifficulty(interval: string | null): Promise<object> {
|
||||||
const difficultyAdjustments = await BlocksRepository.$getBlocksDifficulty(interval);
|
return await BlocksRepository.$getBlocksDifficulty(interval);
|
||||||
const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
|
|
||||||
|
|
||||||
return {
|
|
||||||
adjustments: difficultyAdjustments,
|
|
||||||
oldestIndexedBlockTimestamp: oldestBlock.getTime(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the historical hashrates and oldest indexed block timestamp
|
* Return the historical hashrates and oldest indexed block timestamp
|
||||||
*/
|
*/
|
||||||
public async $getHistoricalHashrates(interval: string | null): Promise<object> {
|
public async $getHistoricalHashrates(interval: string | null): Promise<object> {
|
||||||
const hashrates = await HashratesRepository.$get(interval);
|
return await HashratesRepository.$get(interval);
|
||||||
const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
|
|
||||||
|
|
||||||
return {
|
|
||||||
hashrates: hashrates,
|
|
||||||
oldestIndexedBlockTimestamp: oldestBlock.getTime(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,12 +187,11 @@ class BlocksRepository {
|
|||||||
* Get the oldest indexed block
|
* Get the oldest indexed block
|
||||||
*/
|
*/
|
||||||
public async $oldestBlockTimestamp(): Promise<number> {
|
public async $oldestBlockTimestamp(): Promise<number> {
|
||||||
const query = `SELECT blockTimestamp
|
const query = `SELECT UNIX_TIMESTAMP(blockTimestamp) as blockTimestamp
|
||||||
FROM blocks
|
FROM blocks
|
||||||
ORDER BY height
|
ORDER BY height
|
||||||
LIMIT 1;`;
|
LIMIT 1;`;
|
||||||
|
|
||||||
|
|
||||||
// logger.debug(query);
|
// logger.debug(query);
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const [rows]: any[] = await connection.query(query);
|
const [rows]: any[] = await connection.query(query);
|
||||||
|
@ -588,11 +588,18 @@ class Routes {
|
|||||||
|
|
||||||
public async $getHistoricalHashrate(req: Request, res: Response) {
|
public async $getHistoricalHashrate(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const stats = await mining.$getHistoricalHashrates(req.params.interval ?? null);
|
const hashrates = await mining.$getHistoricalHashrates(req.params.interval ?? null);
|
||||||
|
const difficulty = await mining.$getHistoricalDifficulty(req.params.interval ?? null);
|
||||||
|
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp();
|
||||||
|
console.log(oldestIndexedBlockTimestamp);
|
||||||
res.header('Pragma', 'public');
|
res.header('Pragma', 'public');
|
||||||
res.header('Cache-control', 'public');
|
res.header('Cache-control', 'public');
|
||||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||||
res.json(stats);
|
res.json({
|
||||||
|
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
|
||||||
|
hashrates: hashrates,
|
||||||
|
difficulty: difficulty,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).send(e instanceof Error ? e.message : e);
|
res.status(500).send(e instanceof Error ? e.message : e);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ export class DifficultyChartComponent implements OnInit {
|
|||||||
}),
|
}),
|
||||||
map(data => {
|
map(data => {
|
||||||
const availableTimespanDay = (
|
const availableTimespanDay = (
|
||||||
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp / 1000)
|
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
|
||||||
) / 3600 / 24;
|
) / 3600 / 24;
|
||||||
|
|
||||||
const tableData = [];
|
const tableData = [];
|
||||||
|
@ -23,7 +23,7 @@ import { selectPowerOfTen } from 'src/app/bitcoin.utils';
|
|||||||
})
|
})
|
||||||
export class HashrateChartComponent implements OnInit {
|
export class HashrateChartComponent implements OnInit {
|
||||||
@Input() widget: boolean = false;
|
@Input() widget: boolean = false;
|
||||||
@Input() right: number | string = 10;
|
@Input() right: number | string = 45;
|
||||||
@Input() left: number | string = 75;
|
@Input() left: number | string = 75;
|
||||||
|
|
||||||
radioGroupForm: FormGroup;
|
radioGroupForm: FormGroup;
|
||||||
@ -45,7 +45,7 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
) {
|
) {
|
||||||
this.seoService.setTitle($localize`:@@mining.hashrate:hashrate`);
|
this.seoService.setTitle($localize`:@@mining.hashrate-difficulty:Hashrate and Difficulty`);
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
||||||
}
|
}
|
||||||
@ -57,17 +57,54 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
switchMap((timespan) => {
|
switchMap((timespan) => {
|
||||||
return this.apiService.getHistoricalHashrate$(timespan)
|
return this.apiService.getHistoricalHashrate$(timespan)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(data => {
|
map((data: any) => {
|
||||||
this.prepareChartOptions(data.hashrates.map(val => [val.timestamp * 1000, val.avgHashrate]));
|
const diffFixed = [];
|
||||||
|
diffFixed.push({
|
||||||
|
timestamp: data.hashrates[0].timestamp,
|
||||||
|
difficulty: data.difficulty[0].difficulty
|
||||||
|
});
|
||||||
|
|
||||||
|
let diffIndex = 1;
|
||||||
|
let hashIndex = 0;
|
||||||
|
|
||||||
|
while (hashIndex < data.hashrates.length) {
|
||||||
|
if (diffIndex >= data.difficulty.length) {
|
||||||
|
while (hashIndex < data.hashrates.length) {
|
||||||
|
diffFixed.push({
|
||||||
|
timestamp: data.hashrates[hashIndex].timestamp,
|
||||||
|
difficulty: data.difficulty[data.difficulty.length - 1].difficulty
|
||||||
|
});
|
||||||
|
++hashIndex;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (data.hashrates[hashIndex].timestamp < data.difficulty[diffIndex].timestamp) {
|
||||||
|
diffFixed.push({
|
||||||
|
timestamp: data.hashrates[hashIndex].timestamp,
|
||||||
|
difficulty: data.difficulty[diffIndex - 1].difficulty
|
||||||
|
});
|
||||||
|
++hashIndex;
|
||||||
|
}
|
||||||
|
++diffIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.difficulty = diffFixed;
|
||||||
|
return data;
|
||||||
|
}),
|
||||||
|
tap((data: any) => {
|
||||||
|
this.prepareChartOptions({
|
||||||
|
hashrates: data.hashrates.map(val => [val.timestamp * 1000, val.avgHashrate]),
|
||||||
|
difficulty: data.difficulty.map(val => [val.timestamp * 1000, val.difficulty])
|
||||||
|
});
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}),
|
}),
|
||||||
map(data => {
|
map((data: any) => {
|
||||||
const availableTimespanDay = (
|
const availableTimespanDay = (
|
||||||
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp / 1000)
|
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
|
||||||
) / 3600 / 24;
|
) / 3600 / 24;
|
||||||
return {
|
return {
|
||||||
availableTimespanDay: availableTimespanDay,
|
availableTimespanDay: availableTimespanDay,
|
||||||
data: data.hashrates
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -78,27 +115,25 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
|
|
||||||
prepareChartOptions(data) {
|
prepareChartOptions(data) {
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
color: new graphic.LinearGradient(0, 0, 0, 0.65, [
|
color: [
|
||||||
{ offset: 0, color: '#F4511E' },
|
new graphic.LinearGradient(0, 0, 0, 0.65, [
|
||||||
{ offset: 0.25, color: '#FB8C00' },
|
{ offset: 0, color: '#F4511E' },
|
||||||
{ offset: 0.5, color: '#FFB300' },
|
{ offset: 0.25, color: '#FB8C00' },
|
||||||
{ offset: 0.75, color: '#FDD835' },
|
{ offset: 0.5, color: '#FFB300' },
|
||||||
{ offset: 1, color: '#7CB342' }
|
{ offset: 0.75, color: '#FDD835' },
|
||||||
]),
|
{ offset: 1, color: '#7CB342' }
|
||||||
|
]),
|
||||||
|
'#D81B60',
|
||||||
|
],
|
||||||
grid: {
|
grid: {
|
||||||
right: this.right,
|
right: this.right,
|
||||||
left: this.left,
|
left: this.left,
|
||||||
},
|
},
|
||||||
title: {
|
|
||||||
text: this.widget ? '' : $localize`:@@mining.hashrate:Hashrate`,
|
|
||||||
left: 'center',
|
|
||||||
textStyle: {
|
|
||||||
color: '#FFF',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true,
|
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line'
|
||||||
|
},
|
||||||
backgroundColor: 'rgba(17, 19, 31, 1)',
|
backgroundColor: 'rgba(17, 19, 31, 1)',
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
@ -106,44 +141,91 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
color: '#b1b1b1',
|
color: '#b1b1b1',
|
||||||
},
|
},
|
||||||
borderColor: '#000',
|
borderColor: '#000',
|
||||||
formatter: params => {
|
|
||||||
return `<b style="color: white">${params[0].axisValueLabel}</b><br>
|
|
||||||
${params[0].marker} ${formatNumber(params[0].value[1], this.locale, '1.0-0')} H/s`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisPointer: {
|
|
||||||
type: 'line',
|
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'time',
|
type: 'time',
|
||||||
splitNumber: this.isMobile() ? 5 : 10,
|
splitNumber: this.isMobile() ? 5 : 10,
|
||||||
},
|
},
|
||||||
yAxis: {
|
legend: {
|
||||||
type: 'value',
|
data: [
|
||||||
axisLabel: {
|
{
|
||||||
formatter: (val) => {
|
name: 'Hashrate',
|
||||||
const selectedPowerOfTen: any = selectPowerOfTen(val);
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
const newVal = val / selectedPowerOfTen.divider;
|
textStyle: {
|
||||||
return `${newVal} ${selectedPowerOfTen.unit}H/s`
|
color: 'white',
|
||||||
|
},
|
||||||
|
icon: 'roundRect',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#FFB300',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Difficulty',
|
||||||
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
|
textStyle: {
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
icon: 'roundRect',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#D81B60',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: 'Hashrate',
|
||||||
|
axisLabel: {
|
||||||
|
color: 'rgb(110, 112, 121)',
|
||||||
|
formatter: (val) => {
|
||||||
|
const selectedPowerOfTen: any = selectPowerOfTen(val);
|
||||||
|
const newVal = val / selectedPowerOfTen.divider;
|
||||||
|
return `${newVal} ${selectedPowerOfTen.unit}H/s`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
splitLine: {
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: 'Difficulty',
|
||||||
|
position: 'right',
|
||||||
|
axisLabel: {
|
||||||
|
color: 'rgb(110, 112, 121)',
|
||||||
|
formatter: (val) => {
|
||||||
|
const selectedPowerOfTen: any = selectPowerOfTen(val);
|
||||||
|
const newVal = val / selectedPowerOfTen.divider;
|
||||||
|
return `${newVal} ${selectedPowerOfTen.unit}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Hashrate',
|
||||||
|
showSymbol: false,
|
||||||
|
data: data.hashrates,
|
||||||
|
type: 'line',
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
type: 'dotted',
|
width: 2,
|
||||||
color: '#ffffff66',
|
},
|
||||||
opacity: 0.25,
|
},
|
||||||
|
{
|
||||||
|
yAxisIndex: 1,
|
||||||
|
name: 'Difficulty',
|
||||||
|
showSymbol: false,
|
||||||
|
data: data.difficulty,
|
||||||
|
type: 'line',
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
],
|
||||||
series: {
|
|
||||||
showSymbol: false,
|
|
||||||
data: data,
|
|
||||||
type: 'line',
|
|
||||||
smooth: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dataZoom: this.widget ? null : [{
|
dataZoom: this.widget ? null : [{
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
realtime: true,
|
realtime: true,
|
||||||
|
@ -82,7 +82,7 @@ export class MiningService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const availableTimespanDay = (
|
const availableTimespanDay = (
|
||||||
(new Date().getTime() / 1000) - (stats.oldestIndexedBlockTimestamp / 1000)
|
(new Date().getTime() / 1000) - (stats.oldestIndexedBlockTimestamp)
|
||||||
) / 3600 / 24;
|
) / 3600 / 24;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user