2012-05-09 19:08:25 +00:00
nv . models . pie = function ( ) {
2012-08-17 20:17:33 +00:00
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = { top : 0 , right : 0 , bottom : 0 , left : 0 }
, width = 500
, height = 500
, getValues = function ( d ) { return d . values }
, getX = function ( d ) { return d . x }
, getY = function ( d ) { return d . y }
, id = Math . floor ( Math . random ( ) * 10000 ) //Create semi-unique ID in case user doesn't select one
, color = nv . utils . defaultColor ( )
, valueFormat = d3 . format ( ',.2f' )
, showLabels = true
, donutLabelsOutside = false
, labelThreshold = . 02 //if slice percentage is under this, don't show label
, donut = false
2012-11-24 10:54:20 +00:00
, labelSunbeamLayout = false
2012-08-17 20:17:33 +00:00
, dispatch = d3 . dispatch ( 'chartClick' , 'elementClick' , 'elementDblClick' , 'elementMouseover' , 'elementMouseout' )
;
//============================================================
2012-05-09 19:08:25 +00:00
function chart ( selection ) {
selection . each ( function ( data ) {
2012-06-28 21:14:53 +00:00
var availableWidth = width - margin . left - margin . right ,
availableHeight = height - margin . top - margin . bottom ,
2012-08-17 20:17:33 +00:00
radius = Math . min ( availableWidth , availableHeight ) / 2 ,
2012-11-24 10:54:20 +00:00
arcRadius = radius - ( radius / 5 ) ,
2012-08-17 20:17:33 +00:00
container = d3 . select ( this ) ;
2012-05-09 19:08:25 +00:00
2012-08-17 20:17:33 +00:00
//------------------------------------------------------------
// Setup containers and skeleton of chart
2012-05-11 19:27:07 +00:00
2012-09-10 21:55:32 +00:00
//var wrap = container.selectAll('.nv-wrap.nv-pie').data([data]);
2012-07-26 23:42:42 +00:00
var wrap = container . selectAll ( '.nv-wrap.nv-pie' ) . data ( [ getValues ( data [ 0 ] ) ] ) ;
var wrapEnter = wrap . enter ( ) . append ( 'g' ) . attr ( 'class' , 'nvd3 nv-wrap nv-pie nv-chart-' + id ) ;
2012-06-28 21:14:53 +00:00
var gEnter = wrapEnter . append ( 'g' ) ;
2012-08-17 20:17:33 +00:00
var g = wrap . select ( 'g' ) ;
2012-05-10 22:13:31 +00:00
2012-07-26 23:42:42 +00:00
gEnter . append ( 'g' ) . attr ( 'class' , 'nv-pie' ) ;
2012-05-10 22:13:31 +00:00
2012-06-28 21:14:53 +00:00
wrap . attr ( 'transform' , 'translate(' + margin . left + ',' + margin . top + ')' ) ;
2012-07-26 23:42:42 +00:00
g . select ( '.nv-pie' ) . attr ( 'transform' , 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')' ) ;
2012-05-11 19:27:07 +00:00
2012-08-17 20:17:33 +00:00
//------------------------------------------------------------
container
. on ( 'click' , function ( d , i ) {
dispatch . chartClick ( {
data : d ,
index : i ,
pos : d3 . event ,
id : id
} ) ;
} ) ;
2012-05-11 19:27:07 +00:00
2012-05-09 19:08:25 +00:00
2012-06-28 21:14:53 +00:00
var arc = d3 . svg . arc ( )
2012-11-24 10:54:20 +00:00
. outerRadius ( arcRadius ) ;
2012-05-09 19:08:25 +00:00
2012-06-28 21:14:53 +00:00
if ( donut ) arc . innerRadius ( radius / 2 ) ;
2012-05-10 22:13:31 +00:00
2012-05-11 19:27:07 +00:00
2012-05-14 17:14:12 +00:00
// Setup the Pie chart and choose the data element
2012-05-09 19:08:25 +00:00
var pie = d3 . layout . pie ( )
2012-06-29 18:28:46 +00:00
. sort ( null )
. value ( function ( d ) { return d . disabled ? 0 : getY ( d ) } ) ;
2012-05-09 19:08:25 +00:00
2012-07-26 23:42:42 +00:00
var slices = wrap . select ( '.nv-pie' ) . selectAll ( '.nv-slice' )
2012-06-28 21:14:53 +00:00
. data ( pie ) ;
2012-05-09 19:08:25 +00:00
2012-06-28 21:14:53 +00:00
slices . exit ( ) . remove ( ) ;
2012-05-09 19:08:25 +00:00
2012-07-26 23:42:42 +00:00
var ae = slices . enter ( ) . append ( 'g' )
. attr ( 'class' , 'nv-slice' )
2012-05-10 16:10:15 +00:00
. on ( 'mouseover' , function ( d , i ) {
2012-06-28 21:14:53 +00:00
d3 . select ( this ) . classed ( 'hover' , true ) ;
2012-06-28 23:06:07 +00:00
dispatch . elementMouseover ( {
2012-07-01 05:39:53 +00:00
label : getX ( d . data ) ,
2012-06-28 21:14:53 +00:00
value : getY ( d . data ) ,
2012-06-28 23:06:07 +00:00
point : d . data ,
pointIndex : i ,
2012-06-28 21:14:53 +00:00
pos : [ d3 . event . pageX , d3 . event . pageY ] ,
id : id
} ) ;
2012-05-10 16:10:15 +00:00
} )
. on ( 'mouseout' , function ( d , i ) {
2012-06-28 21:14:53 +00:00
d3 . select ( this ) . classed ( 'hover' , false ) ;
2012-06-28 23:06:07 +00:00
dispatch . elementMouseout ( {
2012-07-01 05:39:53 +00:00
label : getX ( d . data ) ,
2012-06-28 21:14:53 +00:00
value : getY ( d . data ) ,
2012-06-28 23:06:07 +00:00
point : d . data ,
2012-06-28 21:14:53 +00:00
index : i ,
id : id
} ) ;
2012-05-10 16:10:15 +00:00
} )
. on ( 'click' , function ( d , i ) {
2012-06-28 21:14:53 +00:00
dispatch . elementClick ( {
2012-07-01 05:39:53 +00:00
label : getX ( d . data ) ,
2012-06-28 21:14:53 +00:00
value : getY ( d . data ) ,
2012-06-28 23:06:07 +00:00
point : d . data ,
2012-06-28 21:14:53 +00:00
index : i ,
pos : d3 . event ,
id : id
} ) ;
d3 . event . stopPropagation ( ) ;
2012-05-10 22:13:31 +00:00
} )
. on ( 'dblclick' , function ( d , i ) {
dispatch . elementDblClick ( {
2012-07-01 05:39:53 +00:00
label : getX ( d . data ) ,
2012-06-28 21:14:53 +00:00
value : getY ( d . data ) ,
2012-06-28 23:06:07 +00:00
point : d . data ,
2012-05-10 22:13:31 +00:00
index : i ,
pos : d3 . event ,
id : id
} ) ;
2012-06-28 21:14:53 +00:00
d3 . event . stopPropagation ( ) ;
2012-05-10 16:10:15 +00:00
} ) ;
2012-06-28 23:06:07 +00:00
slices
2012-07-26 12:26:01 +00:00
. attr ( 'fill' , function ( d , i ) { return color ( d , i ) ; } )
. attr ( 'stroke' , function ( d , i ) { return color ( d , i ) ; } ) ;
2012-06-28 23:06:07 +00:00
2012-07-26 23:42:42 +00:00
var paths = ae . append ( 'path' )
2012-06-29 18:28:46 +00:00
. each ( function ( d ) { this . _current = d ; } ) ;
2012-05-14 17:14:12 +00:00
//.attr('d', arc);
2012-05-09 19:08:25 +00:00
2012-06-28 23:06:07 +00:00
d3 . transition ( slices . select ( 'path' ) )
2012-05-14 17:14:12 +00:00
. attr ( 'd' , arc )
2012-06-29 18:28:46 +00:00
. attrTween ( 'd' , arcTween ) ;
2012-05-09 19:08:25 +00:00
2012-05-10 22:13:31 +00:00
if ( showLabels ) {
2012-06-28 21:14:53 +00:00
// This does the normal label
2012-07-30 18:57:34 +00:00
var labelsArc = arc ;
if ( donutLabelsOutside ) {
labelsArc = d3 . svg . arc ( ) . outerRadius ( arc . outerRadius ( ) )
}
ae . append ( "g" ) . classed ( "nv-label" , true )
. each ( function ( d , i ) {
var group = d3 . select ( this ) ;
group
. attr ( 'transform' , function ( d ) {
2012-11-24 10:54:20 +00:00
if ( labelSunbeamLayout ) {
d . outerRadius = arcRadius + 10 ; // Set Outer Coordinate
d . innerRadius = arcRadius + 15 ; // Set Inner Coordinate
var rotateAngle = ( d . startAngle + d . endAngle ) / 2 * ( 180 / Math . PI ) ;
if ( ( d . startAngle + d . endAngle ) / 2 < Math . PI ) {
rotateAngle -= 90 ;
} else {
rotateAngle += 90 ;
}
return 'translate(' + labelsArc . centroid ( d ) + ') rotate(' + rotateAngle + ')' ;
} else {
d . outerRadius = radius + 10 ; // Set Outer Coordinate
d . innerRadius = radius + 15 ; // Set Inner Coordinate
return 'translate(' + labelsArc . centroid ( d ) + ')'
}
2012-07-30 18:57:34 +00:00
} ) ;
group . append ( 'rect' )
. style ( 'stroke' , '#fff' )
. style ( 'fill' , '#fff' )
. attr ( "rx" , 3 )
. attr ( "ry" , 3 ) ;
group . append ( 'text' )
2012-11-24 10:54:20 +00:00
. style ( 'text-anchor' , labelSunbeamLayout ? ( ( d . startAngle + d . endAngle ) / 2 < Math . PI ? 'start' : 'end' ) : 'middle' ) //center the text on it's origin or begin/end if orthogonal aligned
2012-07-30 18:57:34 +00:00
. style ( 'fill' , '#000' )
} ) ;
slices . select ( ".nv-label" ) . transition ( )
2012-06-29 18:28:46 +00:00
. attr ( 'transform' , function ( d ) {
2012-11-24 10:54:20 +00:00
if ( labelSunbeamLayout ) {
d . outerRadius = arcRadius + 10 ; // Set Outer Coordinate
d . innerRadius = arcRadius + 15 ; // Set Inner Coordinate
var rotateAngle = ( d . startAngle + d . endAngle ) / 2 * ( 180 / Math . PI ) ;
if ( ( d . startAngle + d . endAngle ) / 2 < Math . PI ) {
rotateAngle -= 90 ;
} else {
rotateAngle += 90 ;
}
return 'translate(' + labelsArc . centroid ( d ) + ') rotate(' + rotateAngle + ')' ;
} else {
d . outerRadius = radius + 10 ; // Set Outer Coordinate
d . innerRadius = radius + 15 ; // Set Inner Coordinate
return 'translate(' + labelsArc . centroid ( d ) + ')'
}
2012-07-30 18:57:34 +00:00
} ) ;
slices . each ( function ( d , i ) {
2012-07-31 19:26:16 +00:00
var slice = d3 . select ( this ) ;
2012-07-30 18:57:34 +00:00
slice
. select ( ".nv-label text" )
2012-11-24 10:54:20 +00:00
. style ( 'text-anchor' , labelSunbeamLayout ? ( ( d . startAngle + d . endAngle ) / 2 < Math . PI ? 'start' : 'end' ) : 'middle' ) //center the text on it's origin or begin/end if orthogonal aligned
2012-07-30 18:57:34 +00:00
. text ( function ( d , i ) {
var percent = ( d . endAngle - d . startAngle ) / ( 2 * Math . PI ) ;
return ( d . value && percent > labelThreshold ) ? getX ( d . data ) : '' ;
} ) ;
2012-07-31 19:26:16 +00:00
var textBox = slice . select ( 'text' ) . node ( ) . getBBox ( ) ;
2012-07-30 18:57:34 +00:00
slice . select ( ".nv-label rect" )
. attr ( "width" , textBox . width + 10 )
. attr ( "height" , textBox . height + 10 )
. attr ( "transform" , function ( ) {
return "translate(" + [ textBox . x - 5 , textBox . y - 5 ] + ")" ;
2012-06-29 19:57:39 +00:00
} ) ;
2012-07-30 18:57:34 +00:00
} ) ;
2012-05-10 16:10:15 +00:00
}
2012-05-09 19:08:25 +00:00
// Computes the angle of an arc, converting from radians to degrees.
function angle ( d ) {
2012-06-28 21:14:53 +00:00
var a = ( d . startAngle + d . endAngle ) * 90 / Math . PI - 90 ;
return a > 90 ? a - 180 : a ;
2012-05-09 19:08:25 +00:00
}
2012-06-29 18:28:46 +00:00
function arcTween ( a ) {
if ( ! donut ) a . innerRadius = 0 ;
var i = d3 . interpolate ( this . _current , a ) ;
this . _current = i ( 0 ) ;
return function ( t ) {
return arc ( i ( t ) ) ;
} ;
}
2012-05-09 19:08:25 +00:00
function tweenPie ( b ) {
2012-06-28 21:14:53 +00:00
b . innerRadius = 0 ;
var i = d3 . interpolate ( { startAngle : 0 , endAngle : 0 } , b ) ;
return function ( t ) {
return arc ( i ( t ) ) ;
} ;
2012-05-09 19:08:25 +00:00
}
} ) ;
return chart ;
}
2012-06-28 21:14:53 +00:00
2012-08-17 20:17:33 +00:00
//============================================================
// Expose Public Variables
//------------------------------------------------------------
2012-06-28 21:14:53 +00:00
chart . dispatch = dispatch ;
2012-05-09 19:08:25 +00:00
chart . margin = function ( _ ) {
if ( ! arguments . length ) return margin ;
2012-08-27 17:30:17 +00:00
margin . top = typeof _ . top != 'undefined' ? _ . top : margin . top ;
margin . right = typeof _ . right != 'undefined' ? _ . right : margin . right ;
margin . bottom = typeof _ . bottom != 'undefined' ? _ . bottom : margin . bottom ;
margin . left = typeof _ . left != 'undefined' ? _ . left : margin . left ;
2012-05-09 19:08:25 +00:00
return chart ;
} ;
chart . width = function ( _ ) {
if ( ! arguments . length ) return width ;
2012-06-28 21:14:53 +00:00
width = _ ;
2012-05-09 19:08:25 +00:00
return chart ;
} ;
chart . height = function ( _ ) {
if ( ! arguments . length ) return height ;
2012-06-28 21:14:53 +00:00
height = _ ;
2012-05-09 19:08:25 +00:00
return chart ;
} ;
2012-07-01 05:39:53 +00:00
chart . values = function ( _ ) {
if ( ! arguments . length ) return getValues ;
getValues = _ ;
2012-05-09 19:08:25 +00:00
return chart ;
} ;
2012-07-01 05:39:53 +00:00
chart . x = function ( _ ) {
if ( ! arguments . length ) return getX ;
getX = _ ;
return chart ;
} ;
chart . y = function ( _ ) {
if ( ! arguments . length ) return getY ;
getY = d3 . functor ( _ ) ;
2012-05-09 19:08:25 +00:00
return chart ;
} ;
2012-05-10 22:13:31 +00:00
chart . showLabels = function ( _ ) {
2012-06-28 21:14:53 +00:00
if ( ! arguments . length ) return showLabels ;
showLabels = _ ;
return chart ;
2012-05-10 22:13:31 +00:00
} ;
2012-11-24 10:54:20 +00:00
chart . labelSunbeamLayout = function ( _ ) {
if ( ! arguments . length ) return labelSunbeamLayout ;
labelSunbeamLayout = _ ;
return chart ;
} ;
2012-05-10 22:13:31 +00:00
2012-07-30 18:57:34 +00:00
chart . donutLabelsOutside = function ( _ ) {
if ( ! arguments . length ) return donutLabelsOutside ;
donutLabelsOutside = _ ;
return chart ;
} ;
2012-05-10 22:13:31 +00:00
chart . donut = function ( _ ) {
2012-06-28 21:14:53 +00:00
if ( ! arguments . length ) return donut ;
donut = _ ;
return chart ;
2012-05-10 22:13:31 +00:00
} ;
2012-05-10 16:10:15 +00:00
chart . id = function ( _ ) {
2012-06-28 21:14:53 +00:00
if ( ! arguments . length ) return id ;
id = _ ;
return chart ;
2012-05-10 16:10:15 +00:00
} ;
2012-05-09 19:08:25 +00:00
2012-06-28 23:06:07 +00:00
chart . color = function ( _ ) {
if ( ! arguments . length ) return color ;
2012-07-26 12:26:01 +00:00
color = nv . utils . getColor ( _ ) ;
2012-06-28 23:06:07 +00:00
return chart ;
} ;
chart . valueFormat = function ( _ ) {
if ( ! arguments . length ) return valueFormat ;
valueFormat = _ ;
return chart ;
} ;
2012-06-29 19:57:39 +00:00
chart . labelThreshold = function ( _ ) {
if ( ! arguments . length ) return labelThreshold ;
labelThreshold = _ ;
return chart ;
} ;
2012-08-17 20:17:33 +00:00
//============================================================
2012-05-10 16:10:15 +00:00
2012-06-28 21:14:53 +00:00
return chart ;
2012-05-09 19:08:25 +00:00
}