+
@@ -59,7 +80,7 @@
{{ pool.rank }} |
 |
{{ pool.name }} |
-
{{ pool.lastEstimatedHashrate }} {{ miningStats.miningUnits.hashrateUnit }} |
+
{{ pool.lastEstimatedHashrate }} {{ miningStats.miningUnits.hashrateUnit }} |
{{ pool['blockText'] }} |
{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%) |
diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.scss b/frontend/src/app/components/pool-ranking/pool-ranking.component.scss
index a41891a8f..f73486395 100644
--- a/frontend/src/app/components/pool-ranking/pool-ranking.component.scss
+++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.scss
@@ -1,13 +1,16 @@
.chart {
max-height: 400px;
@media (max-width: 767.98px) {
- max-height: 300px;
+ max-height: 270px;
}
}
.chart-widget {
width: 100%;
height: 100%;
- max-height: 275px;
+ max-height: 270px;
+ @media (max-width: 767.98px) {
+ max-height: 200px;
+ }
}
.formRadioGroup {
@@ -44,3 +47,59 @@
.loadingGraphs.widget {
top: 25%;
}
+
+.pool-distribution {
+ min-height: 56px;
+ display: block;
+ @media (min-width: 485px) {
+ display: flex;
+ flex-direction: row;
+ }
+ h5 {
+ margin-bottom: 10px;
+ }
+ .item {
+ width: 50%;
+ margin: 0px auto 10px;
+ display: inline-block;
+ @media (min-width: 485px) {
+ margin: 0px auto 10px;
+ }
+ @media (min-width: 785px) {
+ margin: 0px auto 0px;
+ }
+ &:last-child {
+ margin: 0px auto 0px;
+ }
+ &:nth-child(2) {
+ order: 2;
+ @media (min-width: 485px) {
+ order: 3;
+ }
+ }
+ &:nth-child(3) {
+ order: 3;
+ @media (min-width: 485px) {
+ order: 2;
+ display: block;
+ }
+ @media (min-width: 768px) {
+ display: none;
+ }
+ @media (min-width: 992px) {
+ display: block;
+ }
+ }
+ .card-title {
+ font-size: 1rem;
+ color: #4a68b9;
+ }
+ .card-text {
+ font-size: 18px;
+ span {
+ color: #ffffff66;
+ font-size: 12px;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts
index cef04cca5..64641c31d 100644
--- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts
+++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts
@@ -49,7 +49,7 @@ export class PoolRankingComponent implements OnInit {
this.poolsWindowPreference = '1w';
} else {
this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
- this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';
+ this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';
}
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
@@ -85,6 +85,7 @@ export class PoolRankingComponent implements OnInit {
}),
map(data => {
data.pools = data.pools.map((pool: SinglePoolStats) => this.formatPoolUI(pool));
+ data['minersLuck'] = (100 * (data.blockCount / 1008)).toFixed(2); // luck 1w
return data;
}),
tap(data => {
@@ -105,24 +106,40 @@ export class PoolRankingComponent implements OnInit {
}
generatePoolsChartSerieData(miningStats) {
- const poolShareThreshold = this.isMobile() ? 1 : 0.5; // Do not draw pools which hashrate share is lower than that
+ const poolShareThreshold = this.isMobile() ? 2 : 1; // Do not draw pools which hashrate share is lower than that
const data: object[] = [];
+ let totalShareOther = 0;
+ let totalBlockOther = 0;
+ let totalEstimatedHashrateOther = 0;
+
+ let edgeDistance: any = '20%';
+ if (this.isMobile() && this.widget) {
+ edgeDistance = 0;
+ } else if (this.isMobile() && !this.widget || this.widget) {
+ edgeDistance = 35;
+ }
miningStats.pools.forEach((pool) => {
if (parseFloat(pool.share) < poolShareThreshold) {
+ totalShareOther += parseFloat(pool.share);
+ totalBlockOther += pool.blockCount;
+ totalEstimatedHashrateOther += pool.lastEstimatedHashrate;
return;
}
data.push({
itemStyle: {
- color: poolsColor[pool.name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()],
+ color: poolsColor[pool.name.replace(/[^a-zA-Z0-9]/g, '').toLowerCase()],
},
value: pool.share,
- name: pool.name + (this.isMobile() ? `` : ` (${pool.share}%)`),
+ name: pool.name + ((this.isMobile() || this.widget) ? `` : ` (${pool.share}%)`),
label: {
+ overflow: 'none',
color: '#b1b1b1',
- overflow: 'break',
+ alignTo: 'edge',
+ edgeDistance: edgeDistance,
},
tooltip: {
+ show: !this.isMobile() || !this.widget,
backgroundColor: 'rgba(17, 19, 31, 1)',
borderRadius: 4,
shadowColor: 'rgba(0, 0, 0, 0.5)',
@@ -144,6 +161,42 @@ export class PoolRankingComponent implements OnInit {
data: pool.poolId,
} as PieSeriesOption);
});
+
+ // 'Other'
+ data.push({
+ itemStyle: {
+ color: 'grey',
+ },
+ value: totalShareOther,
+ name: 'Other' + (this.isMobile() ? `` : ` (${totalShareOther.toFixed(2)}%)`),
+ label: {
+ overflow: 'none',
+ color: '#b1b1b1',
+ alignTo: 'edge',
+ edgeDistance: edgeDistance
+ },
+ tooltip: {
+ backgroundColor: 'rgba(17, 19, 31, 1)',
+ borderRadius: 4,
+ shadowColor: 'rgba(0, 0, 0, 0.5)',
+ textStyle: {
+ color: '#b1b1b1',
+ },
+ borderColor: '#000',
+ formatter: () => {
+ if (this.poolsWindowPreference === '24h') {
+ return `
${'Other'} (${totalShareOther.toFixed(2)}%)` +
+ totalEstimatedHashrateOther.toString() + ' PH/s' +
+ `
` + totalBlockOther.toString() + ` blocks`;
+ } else {
+ return `
${'Other'} (${totalShareOther.toFixed(2)}%)` +
+ totalBlockOther.toString() + ` blocks`;
+ }
+ }
+ },
+ data: 9999 as any,
+ } as PieSeriesOption);
+
return data;
}
@@ -154,9 +207,22 @@ export class PoolRankingComponent implements OnInit {
}
network = network.charAt(0).toUpperCase() + network.slice(1);
- let radius: any[] = ['20%', '70%'];
- if (this.isMobile() || this.widget) {
- radius = ['20%', '60%'];
+ let radius: any[] = ['20%', '80%'];
+ let top: any = undefined; let bottom = undefined; let height = undefined;
+ if (this.isMobile() && this.widget) {
+ top = -30;
+ height = 270;
+ radius = ['10%', '50%'];
+ } else if (this.isMobile() && !this.widget) {
+ top = 0;
+ height = 300;
+ radius = ['10%', '50%'];
+ } else if (this.widget) {
+ radius = ['15%', '60%'];
+ top = -20;
+ height = 330;
+ } else {
+ top = 35;
}
this.chartOptions = {
@@ -180,14 +246,15 @@ export class PoolRankingComponent implements OnInit {
},
series: [
{
- top: this.widget ? 0 : 35,
+ minShowLabelAngle: 3.6,
+ top: top,
+ bottom: bottom,
+ height: height,
name: 'Mining pool',
type: 'pie',
radius: radius,
data: this.generatePoolsChartSerieData(miningStats),
labelLine: {
- length: this.isMobile() ? 10 : 15,
- length2: this.isMobile() ? 0 : 15,
lineStyle: {
width: 2,
},
@@ -223,6 +290,9 @@ export class PoolRankingComponent implements OnInit {
this.chartInstance = ec;
this.chartInstance.on('click', (e) => {
+ if (e.data.data === 9999) { // "Other"
+ return;
+ }
this.router.navigate(['/mining/pool/', e.data.data]);
});
}
@@ -230,7 +300,7 @@ export class PoolRankingComponent implements OnInit {
/**
* Default mining stats if something goes wrong
*/
- getEmptyMiningStat() {
+ getEmptyMiningStat(): MiningStats {
return {
lastEstimatedHashrate: 'Error',
blockCount: 0,
diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts
index d8760d1f0..a05671257 100644
--- a/frontend/src/app/interfaces/node-api.interface.ts
+++ b/frontend/src/app/interfaces/node-api.interface.ts
@@ -64,7 +64,7 @@ export interface SinglePoolStats {
blockCount: number;
emptyBlocks: number;
rank: number;
- share: string;
+ share: number;
lastEstimatedHashrate: string;
emptyBlockRatio: string;
logo: string;
@@ -75,13 +75,6 @@ export interface PoolsStats {
oldestIndexedBlockTimestamp: number;
pools: SinglePoolStats[];
}
-export interface MiningStats {
- lastEstimatedHashrate: string;
- blockCount: number;
- totalEmptyBlock: number;
- totalEmptyBlockRatio: string;
- pools: SinglePoolStats[];
-}
/**
* Pool component
diff --git a/frontend/src/app/services/mining.service.ts b/frontend/src/app/services/mining.service.ts
index c216515b0..68f7e9da1 100644
--- a/frontend/src/app/services/mining.service.ts
+++ b/frontend/src/app/services/mining.service.ts
@@ -73,7 +73,7 @@ export class MiningService {
const totalEmptyBlockRatio = (totalEmptyBlock / stats.blockCount * 100).toFixed(2);
const poolsStats = stats.pools.map((poolStat) => {
return {
- share: (poolStat.blockCount / stats.blockCount * 100).toFixed(2),
+ share: parseFloat((poolStat.blockCount / stats.blockCount * 100).toFixed(2)),
lastEstimatedHashrate: (poolStat.blockCount / stats.blockCount * stats.lastEstimatedHashrate / hashrateDivider).toFixed(2),
emptyBlockRatio: (poolStat.emptyBlocks / poolStat.blockCount * 100).toFixed(2),
logo: `./resources/mining-pools/` + poolStat.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg',