nv . models . multiBarChart = function ( ) {
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = { top : 30 , right : 20 , bottom : 50 , left : 60 } ,
width = null ,
height = null ,
color = d3 . scale . category20 ( ) . range ( ) ,
showControls = true ,
showLegend = true ,
tooltips = true ,
tooltip = function ( key , x , y , e , graph ) {
return '<h3>' + key + '</h3>' +
'<p>' + y + ' on ' + x + '</p>'
} ,
x , y ; //can be accessed via chart.multibar.[x/y]Scale()
//============================================================
// Private Variables
//------------------------------------------------------------
var multibar = nv . models . multiBar ( ) . stacked ( false ) ,
xAxis = nv . models . axis ( ) . orient ( 'bottom' ) . highlightZero ( false ) , //.showMaxMin(false), //TODO: see why showMaxMin(false) causes no ticks to be shown on x axis
yAxis = nv . models . axis ( ) . orient ( 'left' ) ,
legend = nv . models . legend ( ) . height ( 30 ) ,
controls = nv . models . legend ( ) . height ( 30 ) ,
dispatch = d3 . dispatch ( 'tooltipShow' , 'tooltipHide' ) ;
xAxis . tickFormat ( function ( d ) { return d } ) ;
yAxis . tickFormat ( d3 . format ( ',.1f' ) ) ;
var showTooltip = function ( e , offsetElement ) {
var left = e . pos [ 0 ] + ( offsetElement . offsetLeft || 0 ) ,
top = e . pos [ 1 ] + ( offsetElement . offsetTop || 0 ) ,
x = xAxis . tickFormat ( ) ( multibar . x ( ) ( e . point ) ) ,
y = yAxis . tickFormat ( ) ( multibar . y ( ) ( e . point ) ) ,
content = tooltip ( e . series . key , x , y , e , chart ) ;
nv . tooltip . show ( [ left , top ] , content , e . value < 0 ? 'n' : 's' ) ;
} ;
function chart ( selection ) {
selection . each ( function ( data ) {
var container = d3 . select ( this ) ,
that = this ;
var availableWidth = ( width || parseInt ( container . style ( 'width' ) ) || 960 )
- margin . left - margin . right ,
availableHeight = ( height || parseInt ( container . style ( 'height' ) ) || 400 )
- margin . top - margin . bottom ;
x = multibar . xScale ( ) ;
y = multibar . yScale ( ) ;
var wrap = container . selectAll ( 'g.wrap.multiBarWithLegend' ) . data ( [ data ] ) ;
var gEnter = wrap . enter ( ) . append ( 'g' ) . attr ( 'class' , 'wrap nvd3 multiBarWithLegend' ) . append ( 'g' ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'x axis' ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'y axis' ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'barsWrap' ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'legendWrap' ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'controlsWrap' ) ;
var g = wrap . select ( 'g' ) ;
if ( showLegend ) {
legend . width ( availableWidth / 2 ) ;
g . select ( '.legendWrap' )
. datum ( data )
. call ( legend ) ;
if ( margin . top != legend . height ( ) ) {
margin . top = legend . height ( ) ;
availableHeight = ( height || parseInt ( container . style ( 'height' ) ) || 400 )
- margin . top - margin . bottom ;
}
g . select ( '.legendWrap' )
. attr ( 'transform' , 'translate(' + ( availableWidth / 2 ) + ',' + ( - margin . top ) + ')' ) ;
}
multibar
. width ( availableWidth )
. height ( availableHeight )
. color ( data . map ( function ( d , i ) {
return d . color || color [ i % color . length ] ;
} ) . filter ( function ( d , i ) { return ! data [ i ] . disabled } ) )
if ( showControls ) {
var controlsData = [
{ key : 'Grouped' , disabled : multibar . stacked ( ) } ,
{ key : 'Stacked' , disabled : ! multibar . stacked ( ) }
] ;
controls . width ( 180 ) . color ( [ '#444' , '#444' , '#444' ] ) ;
g . select ( '.controlsWrap' )
. datum ( controlsData )
. attr ( 'transform' , 'translate(0,' + ( - margin . top ) + ')' )
. call ( controls ) ;
}
g . attr ( 'transform' , 'translate(' + margin . left + ',' + margin . top + ')' ) ;
var barsWrap = g . select ( '.barsWrap' )
. datum ( data . filter ( function ( d ) { return ! d . disabled } ) )
d3 . transition ( barsWrap ) . call ( multibar ) ;
xAxis
. scale ( x )
. ticks ( availableWidth / 100 )
. tickSize ( - availableHeight , 0 ) ;
g . select ( '.x.axis' )
. attr ( 'transform' , 'translate(0,' + y . range ( ) [ 0 ] + ')' ) ;
d3 . transition ( g . select ( '.x.axis' ) )
. call ( xAxis ) ;
var xTicks = g . select ( '.x.axis' ) . selectAll ( 'g' ) ;
xTicks
. selectAll ( 'line, text' )
. style ( 'opacity' , 1 )
//TODO: after fixing below problem, make this optional
xTicks
. filter ( function ( d , i ) {
//console.log(d,i,i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0);
return i % Math . ceil ( data [ 0 ] . values . length / ( availableWidth / 100 ) ) !== 0 ;
} )
. style ( 'opacity' , 0 ) //TODO: figure out why even tho the filter does work, all ticks are disappearing
yAxis
. scale ( y )
. ticks ( availableHeight / 36 )
. tickSize ( - availableWidth , 0 ) ;
d3 . transition ( g . select ( '.y.axis' ) )
. call ( yAxis ) ;
//============================================================
// Event Handling/Dispatching (in chart's scope)
//------------------------------------------------------------
legend . dispatch . on ( 'legendClick' , function ( d , i ) {
d . disabled = ! d . disabled ;
if ( ! data . filter ( function ( d ) { return ! d . disabled } ) . length ) {
data . map ( function ( d ) {
d . disabled = false ;
wrap . selectAll ( '.series' ) . classed ( 'disabled' , false ) ;
return d ;
} ) ;
}
selection . transition ( ) . call ( chart ) ;
} ) ;
controls . dispatch . on ( 'legendClick' , function ( d , i ) {
if ( ! d . disabled ) return ;
controlsData = controlsData . map ( function ( s ) {
s . disabled = true ;
return s ;
} ) ;
d . disabled = false ;
switch ( d . key ) {
case 'Grouped' :
multibar . stacked ( false ) ;
break ;
case 'Stacked' :
multibar . stacked ( true ) ;
break ;
}
selection . transition ( ) . call ( chart ) ;
} ) ;
dispatch . on ( 'tooltipShow' , function ( e ) {
if ( tooltips ) showTooltip ( e , that . parentNode )
} ) ;
chart . update = function ( ) { selection . transition ( ) . call ( chart ) } ;
chart . container = this ; // I need a reference to the container in order to have outside code check if the chart is visible or not
} ) ;
return chart ;
}
//============================================================
// Event Handling/Dispatching (out of chart's scope)
//------------------------------------------------------------
multibar . dispatch . on ( 'elementMouseover.tooltip2' , function ( e ) {
e . pos = [ e . pos [ 0 ] + margin . left , e . pos [ 1 ] + margin . top ] ;
dispatch . tooltipShow ( e ) ;
} ) ;
multibar . dispatch . on ( 'elementMouseout.tooltip' , function ( e ) {
dispatch . tooltipHide ( e ) ;
} ) ;
dispatch . on ( 'tooltipHide' , function ( ) {
if ( tooltips ) nv . tooltip . cleanup ( ) ;
} ) ;
//============================================================
// Global getters and setters
//------------------------------------------------------------
chart . dispatch = dispatch ;
chart . legend = legend ;
chart . xAxis = xAxis ;
chart . yAxis = yAxis ;
d3 . rebind ( chart , multibar , 'x' , 'y' , 'xDomain' , 'yDomain' , 'forceX' , 'forceY' , 'clipEdge' , 'id' , 'stacked' , 'delay' ) ;
chart . margin = function ( _ ) {
if ( ! arguments . length ) return margin ;
margin = _ ;
return chart ;
} ;
chart . width = function ( _ ) {
if ( ! arguments . length ) return width ;
width = _ ;
return chart ;
} ;
chart . height = function ( _ ) {
if ( ! arguments . length ) return height ;
height = _ ;
return chart ;
} ;
chart . color = function ( _ ) {
if ( ! arguments . length ) return color ;
color = _ ;
legend . color ( _ ) ;
return chart ;
} ;
chart . showControls = function ( _ ) {
if ( ! arguments . length ) return showControls ;
showControls = _ ;
return chart ;
} ;
chart . showLegend = function ( _ ) {
if ( ! arguments . length ) return showLegend ;
showLegend = _ ;
return chart ;
} ;
chart . tooltips = function ( _ ) {
if ( ! arguments . length ) return tooltips ;
tooltips = _ ;
return chart ;
} ;
chart . tooltipContent = function ( _ ) {
if ( ! arguments . length ) return tooltip ;
tooltip = _ ;
return chart ;
} ;
return chart ;
}