@ -1552,54 +1552,54 @@ nv.models.line = function() {
id = Math . floor ( Math . random ( ) * 10000 ) , //Create semi-unique ID incase user doesn't select one
getX = function ( d ) { return d . x } , // accessor to get the x value from a data point
getY = function ( d ) { return d . y } , // accessor to get the y value from a data point
forceX = [ ] , // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
forceY = [ ] , // List of numbers to Force into the Y scale
interactive = true , // If true, plots a voronoi overlay for advanced point interection
clipEdge = false , // if true, masks lines within x and y scale
clipVoronoi = true , // if true, masks each point with a circle... can turn off to slightly increase performance
xDomain , yDomain ; // Used to manually set the x and y domain, good to save time if calculation has already been made
clipEdge = false ; // if true, masks lines within x and y scale
var x = d3 . scale . linear ( ) ,
y = d3 . scale . linear ( ) ,
scatter = nv . models . scatter ( )
var scatter = nv . models . scatter ( )
. size ( 2.5 ) // default size
. sizeDomain ( [ 2.5 ] ) , //set to speed up calculation, needs to be unset if there is a cstom size accessor
x 0, y0 ,
x , y , x0 , y0 ,
timeoutID ;
function chart ( selection ) {
selection . each ( function ( data ) {
var seriesData = ( xDomain && yDomain ) ? [ ] : // if we know xDomain and yDomain, no need to calculate
data . map ( function ( d ) {
return d . values . map ( function ( d , i ) {
return { x : getX ( d , i ) , y : getY ( d , i ) }
} )
} ) ,
availableWidth = width - margin . left - margin . right ,
var availableWidth = width - margin . left - margin . right ,
availableHeight = height - margin . top - margin . bottom ;
//store old scales if they exist
x0 = x0 || x;
y0 = y0 || y;
x0 = x0 || scatter . xScale ( ) ;
y0 = y0 || scatter . yScale ( ) ;
x . domain ( xDomain || d3 . extent ( d3 . merge ( seriesData ) . map ( function ( d ) { return d . x } ) . concat ( forceX ) ) )
. range ( [ 0 , availableWidth ] ) ;
y . domain ( yDomain || d3 . extent ( d3 . merge ( seriesData ) . map ( function ( d ) { return d . y } ) . concat ( forceY ) ) )
. range ( [ availableHeight , 0 ] ) ;
var wrap = d3 . select ( this ) . selectAll ( 'g.d3line' ) . data ( [ data ] ) ;
var wrapEnter = wrap . enter ( ) . append ( 'g' ) . attr ( 'class' , 'd3line' ) ;
var defsEnter = wrapEnter . append ( 'defs' ) ;
var gEnter = wrapEnter . append ( 'g' ) ;
wrapEnter . append ( 'g' ) . attr ( 'class' , 'scatterWrap' ) ;
var scatterWrap = wrap . select ( '.scatterWrap' ) . datum ( data ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'groups' ) ;
scatter
. id ( id )
. width ( availableWidth )
. height ( availableHeight )
d3 . transition ( scatterWrap ) . call ( scatter ) ;
x = scatter . xScale ( ) ;
y = scatter . yScale ( ) ;
wrap . attr ( 'transform' , 'translate(' + margin . left + ',' + margin . top + ')' ) ;
//TODO: this doesn't remove if turned off after on...
if ( clipEdge ) {
defsEnter . append ( 'clipPath' )
. attr ( 'id' , 'edge-clip-' + id )
@ -1611,6 +1611,8 @@ nv.models.line = function() {
gEnter
. attr ( 'clip-path' , 'url(#edge-clip-' + id + ')' ) ;
scatterWrap
. attr ( 'clip-path' , 'url(#edge-clip-' + id + ')' ) ;
}
@ -1655,21 +1657,6 @@ nv.models.line = function() {
) ;
scatter
. id ( id )
. interactive ( interactive )
. width ( availableWidth )
. height ( availableHeight )
. xDomain ( x . domain ( ) )
. yDomain ( y . domain ( ) )
wrapEnter . append ( 'g' ) . attr ( 'class' , 'scatterWrap' ) ;
var scatterWrap = wrap . select ( '.scatterWrap' ) . datum ( data ) ;
d3 . transition ( scatterWrap ) . call ( scatter ) ;
//store old scales for use in transitions on update, to animate from old to new positions
x0 = x . copy ( ) ;
y0 = y . copy ( ) ;
@ -1682,7 +1669,7 @@ nv.models.line = function() {
chart . dispatch = scatter . dispatch ;
d3 . rebind ( chart , scatter , ' size') ;
d3 . rebind ( chart , scatter , ' interactive', ' size', 'xScale' , 'yScale' , 'zScale' , 'xDomain' , 'yDomain' , 'sizeDomain' , 'forceX' , 'forceY' , 'forceSize' , 'clipVoronoi' , 'clipRadius ') ;
chart . margin = function ( _ ) {
if ( ! arguments . length ) return margin ;
@ -1716,46 +1703,9 @@ nv.models.line = function() {
return chart ;
} ;
chart . xDomain = function ( _ ) {
if ( ! arguments . length ) return xDomain ;
xDomain = _ ;
return chart ;
} ;
chart . yDomain = function ( _ ) {
if ( ! arguments . length ) return yDomain ;
yDomain = _ ;
return chart ;
} ;
chart . forceX = function ( _ ) {
if ( ! arguments . length ) return forceX ;
forceX = _ ;
return chart ;
} ;
chart . forceY = function ( _ ) {
if ( ! arguments . length ) return forceY ;
forceY = _ ;
return chart ;
} ;
chart . interactive = function ( _ ) {
if ( ! arguments . length ) return interactive ;
interactive = _ ;
return chart ;
} ;
chart . clipEdge = function ( _ ) {
if ( ! arguments . length ) return clipEdge ;
clipEdge = _ ;
scatter . clipEdge ( _ ) ;
return chart ;
} ;
chart . clipVoronoi = function ( _ ) {
if ( ! arguments . length ) return clipVoronoi ;
clipVoronoi = _ ;
return chart ;
} ;
@ -3348,9 +3298,12 @@ nv.models.scatter = function() {
height = 500 ,
color = d3 . scale . category20 ( ) . range ( ) , // array of colors to be used in order
id = Math . floor ( Math . random ( ) * 100000 ) , //Create semi-unique ID incase user doesn't selet one
x = d3 . scale . linear ( ) ,
y = d3 . scale . linear ( ) ,
z = d3 . scale . sqrt ( ) , //sqrt because point size is done by area, not radius
getX = function ( d ) { return d . x } , // accessor to get the x value from a data point
getY = function ( d ) { return d . y } , // accessor to get the y value from a data point
getSize = function ( d ) { return d . size } , // accessor to get the point radius from a data point
getSize = function ( d ) { return d . size } , // accessor to get the point radius from a data point //TODO: consider renamig size to z
forceX = [ ] , // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.)
forceY = [ ] , // List of numbers to Force into the Y scale
forceSize = [ ] , // List of numbers to Force into the Size scale
@ -3360,23 +3313,14 @@ nv.models.scatter = function() {
clipRadius = function ( ) { return 25 } , // function to get the radius for point clips
xDomain , yDomain , sizeDomain ; // Used to manually set the x and y domain, good to save time if calculation has already been made
var x = d3 . scale . linear ( ) ,
y = d3 . scale . linear ( ) ,
z = d3 . scale . sqrt ( ) , //sqrt because point size is done by area, not radius
dispatch = d3 . dispatch ( 'elementClick' , 'elementMouseover' , 'elementMouseout' ) , //TODO: consider renaming to elementMouseove and elementMouseout for consistency
var dispatch = d3 . dispatch ( 'elementClick' , 'elementMouseover' , 'elementMouseout' ) , //TODO: consider renaming to elementMouseove and elementMouseout for consistency
x0 , y0 , z0 ,
timeoutID ;
function chart ( selection ) {
selection . each ( function ( data ) {
//var seriesData = data.map(function(d) {
var seriesData = ( xDomain && yDomain && sizeDomain ) ? [ ] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
data . map ( function ( d ) {
return d . values . map ( function ( d , i ) {
return { x : getX ( d , i ) , y : getY ( d , i ) , size : getSize ( d , i ) }
} )
} ) ,
availableWidth = width - margin . left - margin . right ,
var availableWidth = width - margin . left - margin . right ,
availableHeight = height - margin . top - margin . bottom ;
//store old scales if they exist
@ -3394,6 +3338,14 @@ nv.models.scatter = function() {
} ) ;
// slight remap of the data for use in calculating the scales domains
var seriesData = ( xDomain && yDomain && sizeDomain ) ? [ ] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance
data . map ( function ( d ) {
return d . values . map ( function ( d , i ) {
return { x : getX ( d , i ) , y : getY ( d , i ) , size : getSize ( d , i ) }
} )
} ) ;
//TODO: figure out the best way to deal with scales with equal MIN and MAX
//TODO: think of a good way to re-use scales
x . domain ( xDomain || d3 . extent ( d3 . merge ( seriesData ) . map ( function ( d ) { return d . x } ) . concat ( forceX ) ) )
@ -3541,7 +3493,7 @@ nv.models.scatter = function() {
. remove ( ) ;
groups
. attr ( 'class' , function ( d , i ) { return 'group series-' + i } )
. classed ( 'hover' , function ( d ) { return d . hover && ! d . disabled } ) ;
. classed ( 'hover' , function ( d ) { return d . hover } ) ;
d3 . transition ( groups )
. style ( 'fill' , function ( d , i ) { return color [ i % 20 ] } )
. style ( 'stroke' , function ( d , i ) { return color [ i % 20 ] } )
@ -3621,6 +3573,24 @@ nv.models.scatter = function() {
return chart ;
} ;
chart . xScale = function ( _ ) {
if ( ! arguments . length ) return x ;
x = _ ;
return chart ;
} ;
chart . yScale = function ( _ ) {
if ( ! arguments . length ) return y ;
y = _ ;
return chart ;
} ;
chart . zScale = function ( _ ) {
if ( ! arguments . length ) return z ;
z = _ ;
return chart ;
} ;
chart . xDomain = function ( _ ) {
if ( ! arguments . length ) return xDomain ;
xDomain = _ ;
@ -4255,12 +4225,12 @@ nv.models.stackedArea = function() {
width = 960 ,
height = 500 ,
color = d3 . scale . category20 ( ) . range ( ) , // array of colors to be used in order
id = Math . floor ( Math . random ( ) * 100000 ) , //Create semi-unique ID incase user doesn't selet one
getX = function ( d ) { return d . x } , // accessor to get the x value from a data point
getY = function ( d ) { return d . y } , // accessor to get the y value from a data point
style = 'stack' ,
offset = 'zero' ,
order = 'default' ,
interactive = true , // If true, plots a voronoi overlay for advanced point interection
clipEdge = false , // if true, masks lines within x and y scale
xDomain , yDomain ; // Used to manually set the x and y domain, good to save time if calculation has already been made
@ -4279,23 +4249,20 @@ nv.models.stackedArea = function() {
var scatter = nv . models . scatter ( )
. size ( 2.2 ) // default size
. sizeDomain ( [ 2.5 ] ) , //set to speed up calculation, needs to be unset if there is a cstom size accessor
x = d3 . scale . linear ( ) ,
y = d3 . scale . linear ( ) ,
x 2 = d3 . scale . linear ( ) ,
y 2 = d3 . scale . linear ( ) ,
dispatch = d3 . dispatch ( 'tooltipShow' , 'tooltipHide' , 'areaClick' , 'areaMouseover' , 'areaMouseout' ) ;
function chart ( selection ) {
selection . each ( function ( data ) {
// Need to leave data alone to switch between stacked, stream, and expanded
var dataCopy = JSON . parse ( JSON . stringify ( data ) ) ,
seriesData = dataCopy . map ( function ( d ) { //TODO: series data is barely used, can probably remove this pretty easily
return d . values . map ( function ( d , i ) {
return { x : getX ( d , i ) , y : getY ( d , i ) }
} )
} ) ,
availableWidth = width - margin . left - margin . right ,
availableHeight = height - margin . top - margin . bottom ;
//TODO: deal with negative stacked charts
//compute the data based on offset and order (calc's y0 for every point)
dataCopy = d3 . layout . stack ( )
. offset ( offset )
@ -4305,15 +4272,22 @@ nv.models.stackedArea = function() {
( dataCopy ) ;
x . domain ( xDomain || d3 . extent ( d3 . merge ( seriesData ) , function ( d ) { return d . x } ) )
/ *
var seriesData = dataCopy . map ( function ( d ) { //TODO: series data is barely used, can probably remove this pretty easily
return d . values . map ( function ( d , i ) {
return { x : getX ( d , i ) , y : getY ( d , i ) }
} )
} ) ;
x2 . domain ( xDomain || d3 . extent ( d3 . merge ( seriesData ) , function ( d ) { return d . x } ) )
. range ( [ 0 , availableWidth ] ) ;
//TODO: deal with negative stacked charts
y . domain ( yDomain || [ 0 , d3 . max ( dataCopy , function ( d ) { //TODO; if dataCopy not fed {x, y} (custom getX or getY), this will probably cause an error
y2 . domain ( yDomain || [ 0 , d3 . max ( dataCopy , function ( d ) { //TODO; if dataCopy not fed {x, y} (custom getX or getY), this will probably cause an error
return d3 . max ( d . values , function ( d ) { return d . y0 + d . y } )
} ) ] )
. range ( [ availableHeight , 0 ] ) ;
* /
var wrap = d3 . select ( this ) . selectAll ( 'g.d3stackedarea' ) . data ( [ dataCopy ] ) ;
@ -4325,6 +4299,31 @@ nv.models.stackedArea = function() {
gEnter . append ( 'g' ) . attr ( 'class' , 'areaWrap' ) ;
scatter
. width ( availableWidth )
. height ( availableHeight )
. x ( getX )
. y ( function ( d ) { return d . y + d . y0 } ) // TODO: allow for getY to be other than d.y
. forceY ( [ 0 ] )
. color ( data . map ( function ( d , i ) {
return d . color || color [ i % 20 ] ;
} ) . filter ( function ( d , i ) { return ! data [ i ] . disabled } ) ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'scatterWrap' ) ;
var scatterWrap = g . select ( '.scatterWrap' )
. datum ( dataCopy . filter ( function ( d ) { return ! d . disabled } ) )
d3 . transition ( scatterWrap ) . call ( scatter ) ;
x = scatter . xScale ( ) ;
y = scatter . yScale ( ) ;
wrap . attr ( 'transform' , 'translate(' + margin . left + ',' + margin . top + ')' ) ;
@ -4343,26 +4342,6 @@ nv.models.stackedArea = function() {
//TODO: need to also remove area Hover/Click to turn off interactive
if ( interactive ) {
scatter
. width ( availableWidth )
. height ( availableHeight )
. xDomain ( x . domain ( ) )
. yDomain ( y . domain ( ) )
. x ( getX )
. y ( function ( d ) { return d . y + d . y0 } ) // TODO: allow for getY to be other than d.y
. color ( data . map ( function ( d , i ) {
return d . color || color [ i % 20 ] ;
} ) . filter ( function ( d , i ) { return ! data [ i ] . disabled } ) ) ;
gEnter . append ( 'g' ) . attr ( 'class' , 'scatterWrap' ) ;
var scatterWrap = g . select ( '.scatterWrap' )
. datum ( dataCopy . filter ( function ( d ) { return ! d . disabled } ) )
d3 . transition ( scatterWrap ) . call ( scatter ) ;
}
var area = d3 . svg . area ( )
. x ( function ( d , i ) { return x ( getX ( d , i ) ) } )
@ -4439,6 +4418,12 @@ nv.models.stackedArea = function() {
return chart ;
}
chart . dispatch = dispatch ;
chart . scatter = scatter ;
d3 . rebind ( chart , scatter , 'interactive' , 'size' , 'xScale' , 'yScale' , 'zScale' , 'xDomain' , 'yDomain' , 'sizeDomain' , 'forceX' , 'forceY' , 'forceSize' , 'clipVoronoi' , 'clipRadius' ) ;
chart . x = function ( _ ) {
if ( ! arguments . length ) return getX ;
getX = d3 . functor ( _ ) ;
@ -4469,12 +4454,6 @@ nv.models.stackedArea = function() {
return chart ;
} ;
chart . interactive = function ( _ ) {
if ( ! arguments . length ) return interactive ;
interactive = _ ;
return chart ;
} ;
chart . clipEdge = function ( _ ) {
if ( ! arguments . length ) return clipEdge ;
clipEdge = _ ;
@ -4522,8 +4501,6 @@ nv.models.stackedArea = function() {
return chart ;
} ;
chart . dispatch = dispatch ;
chart . scatter = scatter ;
scatter . dispatch . on ( 'elementMouseover.tooltip' , function ( e ) {
@ -4765,7 +4742,7 @@ nv.models.stackedAreaWithLegend = function() {
chart . dispatch = dispatch ;
d3 . rebind ( chart , stacked , 'interactive' );
d3 . rebind ( chart , stacked , 'interactive' , 'clipEdge' );
chart . x = function ( _ ) {
if ( ! arguments . length ) return getX ;