From b775579c6a5a5f971949fd4474d4c454f8dcc831 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Tue, 11 Feb 2014 11:40:26 -0800 Subject: [PATCH 01/12] First-pass at a 'running VMs' graph --- public/lib/stats-vcloud-running.js | 121 +++++++++++++++++++++++++++++ views/dashboard.erb | 12 +++ vmware-host-pooler-api | 15 ++++ 3 files changed, 148 insertions(+) create mode 100644 public/lib/stats-vcloud-running.js diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js new file mode 100644 index 0000000..6a1e3ba --- /dev/null +++ b/public/lib/stats-vcloud-running.js @@ -0,0 +1,121 @@ +var running_url = '/dashboard/stats/vcloud/running'; +var running_height = 150; + +var colorscale = d3.scale.category20(); +var color = {}; + +var stats_vcloud_running__data = {}; +var stats_vcloud_running__svg = {}; + +var stats_vcloud_running__data__total = 0; + +d3.json( running_url, + + function( stats_vcloud_running__data ) { + + ( function tick() { + setTimeout( function() { + + var stats_vcloud_running__data__live = ( function() { + var stats_vcloud_running__data__live = null; + + $.ajax( { + 'url': running_url, + 'async': false, + 'global': false, + 'dataType': 'json', + 'success': function( data ) { + stats_vcloud_running__data__live = data; + } + } ); + + return stats_vcloud_running__data__live; + } )(); + + var stats_vcloud_running__data__keys = []; + var stats_vcloud_running__data__total__tmp = 0; + + for ( var key in stats_vcloud_running__data__live ) { + stats_vcloud_running__data__total__tmp = stats_vcloud_running__data__total__tmp + stats_vcloud_running__data__live[ key ]; + stats_vcloud_running__data__keys.push( key ); + for ( var c = 0; c < Object.keys(stats_vcloud_running__data__keys).length; c++ ) { color[key] = colorscale( c ); } + } + + if ( stats_vcloud_running__data__total__tmp > stats_vcloud_running__data__total ) { + stats_vcloud_running__data__total = stats_vcloud_running__data__total__tmp; + } + + $( '#stats-vcloud-running' ).empty(); + + var x = d3.scale.linear().domain( [ 0, 500 ] ).range( [ 0, document.getElementById( 'stats-vcloud-running' ).offsetWidth ] ); + var y = d3.scale.linear().domain( [ 0, stats_vcloud_running__data__total ] ).range( [ running_height, 0 ] ); + + var area = d3.svg.area() + .x( function( d, i ) { return x( i ); } ) + .y0( function( d ) { return y( d.y0 ); } ) + .y1( function( d ) { return y( d.y0 + d.y ); } ); + + var path = d3.svg.line() + .x( function( d, i ) { return x( i ); } ) + .y( function( d ) { return y( d.y0 + d.y ); } ); + + var stack = d3.layout.stack() + .values( function( d ) { return d.values; } ); + + var stats_vcloud_running__data__stack = {}; + + if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) { + stats_vcloud_running__data[ 'stack' ] = []; + } + + stats_vcloud_running__data[ 'stack' ].push( stats_vcloud_running__data__live ); + + var stats_vcloud_running__data__graph = stack( + stats_vcloud_running__data__keys.sort().map( + function( name ) { + return { + name: name, + values: stats_vcloud_running__data[ 'stack' ].map( function( d ) { + return { y: d[ name ] }; + }) + } + } + ) + ); + + var svg = d3.select( '#stats-vcloud-running' ) + .append( 'svg' ) + .attr( 'height', running_height ) + .attr( 'width', '97%' ) + .style( 'margin-top', '15px' ) + .style( 'margin-bottom', '10px' ) + .append( 'g' ); + + var mysvg = svg.selectAll( '#stats-vcloud-running' ) + .data( stats_vcloud_running__data__graph ) + .enter() + .append( 'g' ); + + mysvg.append( 'path' ) + .attr( 'd', function( d ) { return area( d.values ); } ) + .attr( 'clas', 'area' ) + .attr( 'opacity', '0.25' ) + .style( 'fill', function( d ) { return color[ d.name ]; } ); + + mysvg.append( 'path' ) + .attr( 'd', function( d ) { return path( d.values ); } ) + .attr( 'class', 'line' ) + .attr( 'stroke', function( d ) { return '#888'; } ) + .attr( 'stroke-width', '1' ); + + if ( stats_vcloud_running__data[ 'stack' ].length > 500 ) { + stats_vcloud_running__data[ 'stack' ].shift(); + } + + tick(); + }, 5000 ); + } )(); + + } + +); diff --git a/views/dashboard.erb b/views/dashboard.erb index 8d8b58b..5d0e811 100644 --- a/views/dashboard.erb +++ b/views/dashboard.erb @@ -10,6 +10,18 @@
+ + +
VMs running tests
+ +
+
Loading data... +
+ + + +
+
vCloud pool status
diff --git a/vmware-host-pooler-api b/vmware-host-pooler-api index 49d2bde..10350d1 100755 --- a/vmware-host-pooler-api +++ b/vmware-host-pooler-api @@ -110,6 +110,21 @@ get '/dashboard/stats/vcloud/pool' do JSON.pretty_generate(result) end +get '/dashboard/stats/vcloud/running' do + result = Hash.new + + config[:pools].each do |pool| + running = $redis.scard( 'vmware_host_pool__running__' + pool['name'] ) + + pool['major'] = $1 if pool['name'] =~ /^(\w+)\-/ + + result[pool['major']] = result[pool['major']].to_i + running.to_i + end + + content_type :json + JSON.pretty_generate(result) +end + get '/status' do content_type :json From c8988c3dbf8516f2434f40b19e1618286505d6da Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Tue, 11 Feb 2014 12:51:36 -0800 Subject: [PATCH 02/12] Send 'running' stats to graphite --- vmware-host-pooler | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vmware-host-pooler b/vmware-host-pooler index cf297bd..cfe83ff 100755 --- a/vmware-host-pooler +++ b/vmware-host-pooler @@ -367,9 +367,10 @@ def check_pool pool $redis.scard('vmware_host_pool__pending__'+pool['name']) begin - $graphite.log( - 'vcloud.ready.'+pool['name'], $redis.scard('vmware_host_pool__ready__'+pool['name']) - ) if defined? $graphite + if (defined? $graphite) + $graphite.log('vcloud.ready.'+pool['name'], $redis.scard('vmware_host_pool__ready__'+pool['name'])) + $graphite.log('vcloud.running.'+pool['name'], $redis.scard('vmware_host_pool__running__'+pool['name'])) + end rescue end From 0fccb484551ba91a7ea0755bc540194cb7c3ff0a Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Tue, 11 Feb 2014 14:05:31 -0800 Subject: [PATCH 03/12] Standardize 'running' dashboard API output --- public/lib/stats-vcloud-running.js | 16 +++++++++++----- vmware-host-pooler-api | 5 +++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index 6a1e3ba..cabb4d4 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -36,7 +36,7 @@ d3.json( running_url, var stats_vcloud_running__data__total__tmp = 0; for ( var key in stats_vcloud_running__data__live ) { - stats_vcloud_running__data__total__tmp = stats_vcloud_running__data__total__tmp + stats_vcloud_running__data__live[ key ]; + stats_vcloud_running__data__total__tmp = stats_vcloud_running__data__total__tmp + stats_vcloud_running__data__live[ key ][ 'running' ]; stats_vcloud_running__data__keys.push( key ); for ( var c = 0; c < Object.keys(stats_vcloud_running__data__keys).length; c++ ) { color[key] = colorscale( c ); } } @@ -64,11 +64,17 @@ d3.json( running_url, var stats_vcloud_running__data__stack = {}; - if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) { - stats_vcloud_running__data[ 'stack' ] = []; - } + if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) { + stats_vcloud_running__data[ 'stack' ] = []; + } - stats_vcloud_running__data[ 'stack' ].push( stats_vcloud_running__data__live ); + stats_vcloud_running__data[ 'tmp' ] = {}; + + for ( var key in stats_vcloud_running__data__live ) { + stats_vcloud_running__data[ 'tmp' ][ key ] = stats_vcloud_running__data__live[ key ][ 'running' ]; + } + + stats_vcloud_running__data[ 'stack' ].push( stats_vcloud_running__data[ 'tmp' ] ); var stats_vcloud_running__data__graph = stack( stats_vcloud_running__data__keys.sort().map( diff --git a/vmware-host-pooler-api b/vmware-host-pooler-api index 10350d1..84b78b7 100755 --- a/vmware-host-pooler-api +++ b/vmware-host-pooler-api @@ -115,10 +115,11 @@ get '/dashboard/stats/vcloud/running' do config[:pools].each do |pool| running = $redis.scard( 'vmware_host_pool__running__' + pool['name'] ) - pool['major'] = $1 if pool['name'] =~ /^(\w+)\-/ - result[pool['major']] = result[pool['major']].to_i + running.to_i + result[pool['major']] ||= Hash.new + + result[pool['major']]['running'] = result[pool['major']]['running'].to_i + running.to_i end content_type :json From 362d08057845b6e45e8cacb3fd1a7ec9869f9c38 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Tue, 11 Feb 2014 15:11:43 -0800 Subject: [PATCH 04/12] Pull 'running' history from graphite on dashboard init --- public/lib/stats-vcloud-running.js | 26 +++++++++++++++++++--- vmware-host-pooler-api | 35 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index cabb4d4..82368f7 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -9,10 +9,32 @@ var stats_vcloud_running__svg = {}; var stats_vcloud_running__data__total = 0; -d3.json( running_url, +d3.json( running_url+'?history=1', function( stats_vcloud_running__data ) { + if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) { + stats_vcloud_running__data[ 'stack' ] = []; + } + + var mytmphash = []; + + for ( var c = 0; c < 500; c++ ) { + for ( var key in stats_vcloud_running__data ) { + if ( ! stats_vcloud_running__data[ key ][ 'history' ] ) { + continue; + } + + if ( ! stats_vcloud_running__data[ key ][ 'history' ][ c ] ) { + mytmphash[ key ] = 0; + } + else { + mytmphash[ key ] = stats_vcloud_running__data[ key ][ 'history' ][ c ]; + } + } + stats_vcloud_running__data[ 'stack' ].push( mytmphash ); + } + ( function tick() { setTimeout( function() { @@ -62,8 +84,6 @@ d3.json( running_url, var stack = d3.layout.stack() .values( function( d ) { return d.values; } ); - var stats_vcloud_running__data__stack = {}; - if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) { stats_vcloud_running__data[ 'stack' ] = []; } diff --git a/vmware-host-pooler-api b/vmware-host-pooler-api index 84b78b7..283203a 100755 --- a/vmware-host-pooler-api +++ b/vmware-host-pooler-api @@ -122,6 +122,41 @@ get '/dashboard/stats/vcloud/running' do result[pool['major']]['running'] = result[pool['major']]['running'].to_i + running.to_i end + if ( params[:history] ) + if ( config[:config]['graphite'] ) + history ||= Hash.new + + begin + buffer = open( 'http://'+config[:config]['graphite']+'/render?target=vcloud.running.*&from=-1hour&format=json' ).read + history = JSON.parse( buffer ) + + history.each do |pool| + if pool['target'] =~ /.*\.(.*)$/ + pool['name'] = $1 + pool['major'] = $1 if pool['name'] =~ /^(\w+)\-/ + + if ( result[pool['major']] ) + pool['last'] = result[pool['major']]['running'] + result[pool['major']]['history'] ||= Array.new + + pool['datapoints'].each do |metric| + 3.times do |n| + if ( metric[0] ) + pool['last'] = metric[0].to_i + result[pool['major']]['history'].push( metric[0].to_i ) + else + result[pool['major']]['history'].push( pool['last'] ) + end + end + end + end + end + end + rescue + end + end + end + content_type :json JSON.pretty_generate(result) end From 709dc97d04440e382cdeb69938f85a1c29deeb8e Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Wed, 12 Feb 2014 16:27:14 -0800 Subject: [PATCH 05/12] Clean up 'running' history-pulling code --- public/lib/stats-vcloud-running.js | 20 +++++++------------ vmware-host-pooler-api | 32 ++++++++++++++---------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index 82368f7..fad8e03 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -17,22 +17,16 @@ d3.json( running_url+'?history=1', stats_vcloud_running__data[ 'stack' ] = []; } - var mytmphash = []; + for ( var key in stats_vcloud_running__data ) { + if ( stats_vcloud_running__data[ key ][ 'history' ] ) { + for ( var c = 0; c < stats_vcloud_running__data[ key ][ 'history' ].length; c++ ) { + if ( typeof stats_vcloud_running__data[ 'stack' ][ c ] === 'undefined' ) { + stats_vcloud_running__data[ 'stack' ][ c ] = {}; + } - for ( var c = 0; c < 500; c++ ) { - for ( var key in stats_vcloud_running__data ) { - if ( ! stats_vcloud_running__data[ key ][ 'history' ] ) { - continue; - } - - if ( ! stats_vcloud_running__data[ key ][ 'history' ][ c ] ) { - mytmphash[ key ] = 0; - } - else { - mytmphash[ key ] = stats_vcloud_running__data[ key ][ 'history' ][ c ]; + stats_vcloud_running__data[ 'stack' ][ c ][ key ] = stats_vcloud_running__data[ key ][ 'history' ][ c ]; } } - stats_vcloud_running__data[ 'stack' ].push( mytmphash ); } ( function tick() { diff --git a/vmware-host-pooler-api b/vmware-host-pooler-api index 283203a..fe9c4e3 100755 --- a/vmware-host-pooler-api +++ b/vmware-host-pooler-api @@ -124,32 +124,30 @@ get '/dashboard/stats/vcloud/running' do if ( params[:history] ) if ( config[:config]['graphite'] ) - history ||= Hash.new - begin buffer = open( 'http://'+config[:config]['graphite']+'/render?target=vcloud.running.*&from=-1hour&format=json' ).read - history = JSON.parse( buffer ) - - history.each do |pool| + JSON.parse( buffer ).each do |pool| if pool['target'] =~ /.*\.(.*)$/ pool['name'] = $1 + pool['major'] = $1 if pool['name'] =~ /^(\w+)\-/ - if ( result[pool['major']] ) - pool['last'] = result[pool['major']]['running'] - result[pool['major']]['history'] ||= Array.new + result[pool['major']]['history'] ||= Array.new - pool['datapoints'].each do |metric| - 3.times do |n| - if ( metric[0] ) - pool['last'] = metric[0].to_i - result[pool['major']]['history'].push( metric[0].to_i ) - else - result[pool['major']]['history'].push( pool['last'] ) - end - end + for i in 0..pool['datapoints'].length + if ( + pool['datapoints'][i] and + pool['datapoints'][i][0] + ) + pool['last'] = pool['datapoints'][i][0] + + result[pool['major']]['history'][i] ||= 0 + result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['datapoints'][i][0].to_i + else + result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['last'].to_i end end + end end rescue From cdffded5ab801f9ee6eee5ff4e67aafa483679b8 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 09:24:57 -0800 Subject: [PATCH 06/12] Squashing SVG heights to fit everything in a 1920x1080 display --- public/dashboard.css | 2 +- public/lib/stats-vcloud-pool.js | 4 ++-- public/lib/stats-vcloud-running.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/dashboard.css b/public/dashboard.css index 1e6b760..1f87f7e 100644 --- a/public/dashboard.css +++ b/public/dashboard.css @@ -1,7 +1,7 @@ body, #content { background: #fff; - margin-top: 20px; + margin-top: 10px; margin-left: auto; margin-right: auto; } diff --git a/public/lib/stats-vcloud-pool.js b/public/lib/stats-vcloud-pool.js index dd6cd8a..1bf5c38 100644 --- a/public/lib/stats-vcloud-pool.js +++ b/public/lib/stats-vcloud-pool.js @@ -1,6 +1,6 @@ var pool_url = '/dashboard/stats/vcloud/pool'; var pool_width = 130; -var pool_height = 85; +var pool_height = 80; var stats_vcloud_pool__data = {}; var stats_vcloud_pool__svg = {}; @@ -70,7 +70,7 @@ d3.json( pool_url+'?history=1', stats_vcloud_pool__svg[ pool ] = d3.select( '#stats-vcloud-pool' ) .append( 'svg' ) .style( 'margin', '15px 0px 0px 0px' ) - .style( 'padding', '0px 10px 20px 10px' ) + .style( 'padding', '0px 10px 10px 10px' ) .attr( 'width', pool_width ) .attr( 'height', pool_height ); diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index fad8e03..7024d9a 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -1,5 +1,5 @@ var running_url = '/dashboard/stats/vcloud/running'; -var running_height = 150; +var running_height = 120; var colorscale = d3.scale.category20(); var color = {}; From 978a9b80a082ce5c180b6c34e6de9cbf8b5199d5 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 09:53:21 -0800 Subject: [PATCH 07/12] Expand history array --- public/lib/stats-vcloud-running.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index 7024d9a..bbc3857 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -15,6 +15,7 @@ d3.json( running_url+'?history=1', if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) { stats_vcloud_running__data[ 'stack' ] = []; + stats_vcloud_running__data[ 'stack_t' ] = []; } for ( var key in stats_vcloud_running__data ) { @@ -29,6 +30,15 @@ d3.json( running_url+'?history=1', } } + for ( var c in stats_vcloud_running__data[ 'stack' ] ) { + for ( var n = 0; n < 8; n++ ) { + stats_vcloud_running__data[ 'stack_t' ].push( stats_vcloud_running__data[ 'stack' ][ c ] ); + } + } + + stats_vcloud_running__data[ 'stack' ] = stats_vcloud_running__data[ 'stack_t' ]; + delete stats_vcloud_running__data[ 'stack_t' ]; + ( function tick() { setTimeout( function() { From 52cd9bc1287c5784df05254d51ffb0c9d1092ac1 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 09:58:49 -0800 Subject: [PATCH 08/12] Right-margin --- public/dashboard.css | 1 + public/lib/stats-vcloud-running.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/public/dashboard.css b/public/dashboard.css index 1f87f7e..8eb055d 100644 --- a/public/dashboard.css +++ b/public/dashboard.css @@ -117,6 +117,7 @@ body, .module { margin-top: 5px; margin-left: 25px; + margin-right: 25px; font: 13px 'PT Sans', sans-serif; line-height: 20px; color: #888; diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index bbc3857..e101892 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -116,7 +116,6 @@ d3.json( running_url+'?history=1', var svg = d3.select( '#stats-vcloud-running' ) .append( 'svg' ) .attr( 'height', running_height ) - .attr( 'width', '97%' ) .style( 'margin-top', '15px' ) .style( 'margin-bottom', '10px' ) .append( 'g' ); From 0b07ff91f1d44cb1e7f88473d8d000b66de8390d Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 11:46:01 -0800 Subject: [PATCH 09/12] Add a graph legend --- public/lib/stats-vcloud-running.js | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index e101892..977de5d 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -137,6 +137,42 @@ d3.json( running_url+'?history=1', .attr( 'stroke', function( d ) { return '#888'; } ) .attr( 'stroke-width', '1' ); + stats_vcloud_running__data__keys.sort().map( + function( key ) { + stats_vcloud_running__svg[ key ] = d3.select( '#stats-vcloud-running' ) + .append( 'svg' ) + .style( 'margin', '0px 0px 0px 0px' ) + .style( 'padding', '0px 10px 10px 10px' ) + .attr( 'width', '130px' ) + .attr( 'height', '12px' ); + + stats_vcloud_running__svg[ key ] + .append( 'rect' ) + .attr( { + 'x': '5', + 'y': '3', + 'width': '10', + 'height': '10', + 'opacity': '0.25', + 'fill': function( d ) { return color[ key ]; } + } ); + + stats_vcloud_running__svg[ key ] + .append( 'text' ) + .text( + ( key ) + ) + .attr( { + 'x': '20', + 'y': '12', + 'font-face': '\'PT Sans\', sans-serif', + 'font-size': '12px', + 'font-weight': 'bold', + 'fill': '#888' + } ); + } + ); + if ( stats_vcloud_running__data[ 'stack' ].length > 500 ) { stats_vcloud_running__data[ 'stack' ].shift(); } From 97912d71d54dccb1e67a632ae6aaae20a4006e1a Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 11:58:38 -0800 Subject: [PATCH 10/12] width: 100% for Firefox --- public/lib/stats-vcloud-running.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index 977de5d..98f5859 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -116,6 +116,7 @@ d3.json( running_url+'?history=1', var svg = d3.select( '#stats-vcloud-running' ) .append( 'svg' ) .attr( 'height', running_height ) + .attr( 'width', '100%' ) .style( 'margin-top', '15px' ) .style( 'margin-bottom', '10px' ) .append( 'g' ); From 393c4a3121c67cbb57c361ec5c434c0cba490776 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 12:27:41 -0800 Subject: [PATCH 11/12] Slightly squash logo --- public/dashboard.css | 4 ++-- public/img/logo.jpg | Bin 12559 -> 10348 bytes views/layout.erb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/dashboard.css b/public/dashboard.css index 8eb055d..3134e8d 100644 --- a/public/dashboard.css +++ b/public/dashboard.css @@ -1,7 +1,7 @@ body, #content { background: #fff; - margin-top: 10px; + margin-top: 0px; margin-left: auto; margin-right: auto; } @@ -27,7 +27,7 @@ body, float: right; position: relative; right: 30px; - top: 100px; + top: 90px; font: 50px 'PT Sans', sans-serif; letter-spacing: -0.05em; color: #444; diff --git a/public/img/logo.jpg b/public/img/logo.jpg index 5f4b0867cc72bf1d129afac2f920da5bf82a075e..611846a065e07a387a6e7124db97f944a2afa478 100644 GIT binary patch literal 10348 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 literal 12559 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 diff --git a/views/layout.erb b/views/layout.erb index 1f070af..2f0b10f 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -17,7 +17,7 @@
From 82c2afa619e504c7d04953b1f56e3808f13cd470 Mon Sep 17 00:00:00 2001 From: Scott Schneider Date: Thu, 13 Feb 2014 15:43:44 -0800 Subject: [PATCH 12/12] Grow/shrink graph based on max stacked value --- public/lib/stats-vcloud-running.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/public/lib/stats-vcloud-running.js b/public/lib/stats-vcloud-running.js index 98f5859..d7072fc 100644 --- a/public/lib/stats-vcloud-running.js +++ b/public/lib/stats-vcloud-running.js @@ -59,18 +59,12 @@ d3.json( running_url+'?history=1', } )(); var stats_vcloud_running__data__keys = []; - var stats_vcloud_running__data__total__tmp = 0; for ( var key in stats_vcloud_running__data__live ) { - stats_vcloud_running__data__total__tmp = stats_vcloud_running__data__total__tmp + stats_vcloud_running__data__live[ key ][ 'running' ]; stats_vcloud_running__data__keys.push( key ); for ( var c = 0; c < Object.keys(stats_vcloud_running__data__keys).length; c++ ) { color[key] = colorscale( c ); } } - if ( stats_vcloud_running__data__total__tmp > stats_vcloud_running__data__total ) { - stats_vcloud_running__data__total = stats_vcloud_running__data__total__tmp; - } - $( '#stats-vcloud-running' ).empty(); var x = d3.scale.linear().domain( [ 0, 500 ] ).range( [ 0, document.getElementById( 'stats-vcloud-running' ).offsetWidth ] ); @@ -113,6 +107,14 @@ d3.json( running_url+'?history=1', ) ); + stats_vcloud_running__data__total = d3.max( + stats_vcloud_running__data__graph, function( layer ) { + return d3.max( layer.values, function( d ) { + return d.y0 + d.y; + } ); + } + ); + var svg = d3.select( '#stats-vcloud-running' ) .append( 'svg' ) .attr( 'height', running_height )