diff --git a/models/history.js b/models/history.js index 2727f89..958b1de 100644 --- a/models/history.js +++ b/models/history.js @@ -272,6 +272,32 @@ History.prototype.getGasSpending = function() return gasSpending; } +History.prototype.getAvgHashrate = function() +{ + if(this._items.length === 0) + return 0; + + var difficultyHistory = _(this._items) + .map(function(item) + { + return item.block.difficulty; + }) + .value(); + + var avgDifficulty = _.sum(difficultyHistory)/difficultyHistory.length; + + var blocktimeHistory = _(this._items) + .map(function(item) + { + return item.block.time; + }) + .value(); + + var avgBlocktime = _.sum(blocktimeHistory)/blocktimeHistory.length; + + return avgDifficulty/1000 * 12 * (12/avgBlocktime); +} + History.prototype.getCharts = function() { var chartHistory = _(this._items) @@ -295,12 +321,14 @@ History.prototype.getCharts = function() var chart = { height: _.pluck(chartHistory, 'height'), blocktime: _.pluck(chartHistory, 'blocktime'), + avgBlocktime: _.sum(_.pluck(chartHistory, 'blocktime')) / (chartHistory.length === 0 ? 1 : chartHistory.length), difficulty: _.pluck(chartHistory, 'difficulty'), uncles: _.pluck(chartHistory, 'uncles'), transactions: _.pluck(chartHistory, 'transactions'), gasSpending: _.pluck(chartHistory, 'gasSpending'), propagation: this.getBlockPropagation(), - uncleCount: this.getUncleCount() + uncleCount: this.getUncleCount(), + avgHashrate: this.getAvgHashrate() } return chart; diff --git a/package.json b/package.json index 678766d..3def593 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "eth-netstats", "description": "Ethereum Network Intelligence dashboard", - "version": "0.0.5", + "version": "0.0.6", "private": true, "engines": { "node": "0.12.0", diff --git a/public/css/style.css b/public/css/style.css index df778ca..e290851 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -137,7 +137,8 @@ span.small-title span.small { } .big-info.chart .big-details { - padding-top: 8px; + position: absolute; + top: 40px; } .big-info.chart { @@ -202,7 +203,8 @@ span.small-title span.small { padding: 5px 15px; } -.second-row .box i { +.second-row .box i, +.big-info.chart i { position: relative; top: 2px; left: -3px; @@ -213,13 +215,27 @@ span.small-title span.small { float: left; } -.second-row .box .small-value { +.big-info.chart i { + font-size: 24px; + top: -2px; +} + +.small-value { font-weight: 300; -webkit-font-smoothing: subpixel-antialiased; -moz-osx-font-smoothing: auto; float: right; } +.second-row .box .small-value { + float: right; +} +.big-info .small-value { + position: absolute; + right: 14px; + top: 10px; +} + table i { -webkit-font-smoothing: subpixel-antialiased; -moz-osx-font-smoothing: auto; diff --git a/public/js/controllers.js b/public/js/controllers.js index 32e37f8..8a599aa 100644 --- a/public/js/controllers.js +++ b/public/js/controllers.js @@ -14,6 +14,7 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { $scope.lastDifficulty = 0; $scope.upTimeTotal = 0; $scope.avgBlockTime = 0; + $scope.avgHashrate = 0; $scope.uncleCount = 0; $scope.bestStats = {}; @@ -124,9 +125,12 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { data.stats.hashrate = 0; var index = findIndex({id: data.id}); - $scope.nodes[index].stats = data.stats; - $scope.nodes[index].history = data.history; - makePeerPropagationChart($scope.nodes[index]); + + if(typeof $scope.nodes[index].stats !== 'undefined') { + $scope.nodes[index].stats = data.stats; + $scope.nodes[index].history = data.history; + makePeerPropagationChart($scope.nodes[index]); + } break; @@ -150,6 +154,8 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { case "charts": $scope.lastBlocksTime = data.blocktime; + $scope.avgBlockTime = data.avgBlocktime; + $scope.avgHashrate = data.avgHashrate; $scope.difficultyChart = data.difficulty; $scope.transactionDensity = data.transactions; $scope.gasSpending = data.gasSpending; @@ -174,7 +180,10 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { break; case "latency": - $scope.nodes[findIndex({id: data.id})].stats.latency = data.latency; + var node = $scope.nodes[findIndex({id: data.id})]; + + if(typeof node.stats !== 'undefined' && typeof node.stats.latency !== 'undefined') + $scope.nodes[findIndex({id: data.id})].stats.latency = data.latency; break; @@ -273,10 +282,6 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { } } - $scope.avgBlockTime = _.max($scope.nodes, function(node) { - return parseInt(node.stats.block.number); - }).stats.blocktimeAvg; - $scope.upTimeTotal = _.reduce($scope.nodes, function(total, node) { return total + node.stats.uptime; }, 0) / $scope.nodes.length; diff --git a/public/js/filters.js b/public/js/filters.js index bfb97db..04075c5 100644 --- a/public/js/filters.js +++ b/public/js/filters.js @@ -134,6 +134,9 @@ angular.module('netStatsApp.filters', []) }) .filter('hashFilter', function() { return function(hash) { + if(typeof hash === 'undefined') + return "?"; + if(hash.substr(0,2) === '0x') hash = hash.substr(2,64); diff --git a/views/index.jade b/views/index.jade index 4b91260..e3da879 100644 --- a/views/index.jade +++ b/views/index.jade @@ -3,22 +3,6 @@ extends layout block content div.container-fluid(ng-controller='StatsCtrl') div.row(ng-cloak) - div.col-xs-2.stat-holder - div.big-info.nodesactive(class="{{ nodesActive | nodesActiveClass : nodesTotal }}") - div.pull-left.icon-full-width - i.icon-node - div.pull-left - span.small-title active nodes - span.big-details {{nodesActive}}/{{nodesTotal}} - div.clearfix - //- div.col-xs-2.stat-holder - //- div.big-info.uptime(class="{{ upTimeTotal | upTimeClass : true }}") - //- div.pull-left.icon-full-width - //- i.icon-bulb - //- div.pull-left - //- span.small-title up-time - //- span.big-details {{ upTimeTotal | upTimeFilter }} - //- div.clearfix div.col-xs-2.stat-holder div.big-info.bestblock.text-info div.pull-left.icon-full-width @@ -27,14 +11,6 @@ block content span.small-title best block span.big-details {{'#'}}{{ bestBlock | number}} div.clearfix - div.col-xs-2.stat-holder - div.big-info.difficulty.text-info - div.pull-left.icon-full-width - i.icon-difficulty - div.pull-left - span.small-title difficulty - span.big-details {{ lastDifficulty | number }} - div.clearfix div.col-xs-2.stat-holder div.big-info.uncleCount.text-info div.pull-left.icon-full-width @@ -60,22 +36,39 @@ block content span.small-title avg block time span.big-details {{ avgBlockTime | avgTimeFilter }} div.clearfix + div.col-xs-2.stat-holder + div.big-info.difficulty.text-orange + div.pull-left.icon-full-width + i.icon-hashrate + div.pull-left + span.small-title avg network hashrate + span.big-details {{ avgHashrate | number : 1 }} MH/s + div.clearfix + div.col-xs-2.stat-holder + div.big-info.difficulty.text-danger + div.pull-left.icon-full-width + i.icon-difficulty + div.pull-left + span.small-title difficulty + span.big-details {{ lastDifficulty | number }} + div.clearfix + div.clearfix div.row(ng-cloak) div.col-xs-8.stats-boxes(style="padding-top: 0px;") div.row.second-row - //- div.col-xs-3.stat-holder.box - //- div.active-nodes(class="{{ nodesActive | nodesActiveClass : nodesTotal }}") - //- i.icon-node - //- span.small-title active nodes - //- span.small-value {{nodesActive}}/{{nodesTotal}} div.col-xs-3.stat-holder.box - div.difficulty.text-info - i.icon-difficulty - span.small-title difficulty - span.small-value {{ lastDifficulty | number }} + div.active-nodes(class="{{ nodesActive | nodesActiveClass : nodesTotal }}") + i.icon-node + span.small-title active nodes + span.small-value {{nodesActive}}/{{nodesTotal}} + //- div.col-xs-3.stat-holder.box + //- div.difficulty.text-info + //- i.icon-difficulty + //- span.small-title difficulty + //- span.small-value {{ lastDifficulty | number }} div.col-xs-3.stat-holder.box div.gasprice.text-info i.icon-gasprice @@ -94,18 +87,24 @@ block content div.row div.col-xs-3.stat-holder - div.big-info.chart + div.big-info.chart(class="{{ avgBlockTime | avgTimeClass }}") + //- i.icon-time span.small-title block time + //- span.small-value {{ avgBlockTime | avgTimeFilter }} span.big-details.spark-blocktimes div.col-xs-3.stat-holder - div.big-info.chart + div.big-info.chart.text-info + //- i.icon-difficulty span.small-title difficulty + //- span.small-value {{ lastDifficulty | number }} span.big-details.spark-difficulty div.col-xs-3.stat-holder.xpull-right - div.big-info.chart.xdouble-chart + div.big-info.chart.xdouble-chart.text-info + //- i.icon-gas span.small-title block propagation + //- span.small-value {{ lastDifficulty | number }} histogram.big-details.d3-blockpropagation(data="blockPropagationChart") div.col-xs-3.stat-holder.pull-right @@ -118,18 +117,22 @@ block content div.clearfix div.col-xs-3.stat-holder - div.big-info.chart + div.big-info.chart.text-info + //- i.icon-uncle span.small-title uncle count #[ ] span.small (25 blocks per bar) + //- span.small-value {{ bestStats.block.uncles.length }}/{{ uncleCount }} span.big-details.spark-uncles div.col-xs-3.stat-holder - div.big-info.chart + div.big-info.chart.text-info + //- i.icon-uncle span.small-title transactions span.big-details.spark-transactions div.col-xs-3.stat-holder - div.big-info.chart + div.big-info.chart.text-info + //- i.icon-gasprice span.small-title gas spending span.big-details.spark-gasspending