@ -304,8 +304,9 @@ nv.models.axis = function() {
showMaxMin = true , //TODO: showMaxMin should be disabled on all ordinal scaled axes
highlightZero = true ,
rotateLabels = 0 ,
rotateYLabel = true ;
margin = { top : 0 , right : 0 , bottom : 0 , left : 0 }
rotateYLabel = true ,
margin = { top : 0 , right : 0 , bottom : 0 , left : 0 } ,
ticks = null ;
var axis = d3 . svg . axis ( )
. scale ( scale )
@ -322,8 +323,11 @@ nv.models.axis = function() {
var gEnter = wrapEnter . append ( 'g' ) ;
var g = wrap . select ( 'g' )
if ( axis . orient ( ) == 'top' || axis . orient ( ) == 'bottom' )
if ( ticks !== null ) {
axis . ticks ( ticks ) ;
} else if ( axis . orient ( ) == 'top' || axis . orient ( ) == 'bottom' ) {
axis . ticks ( Math . abs ( scale . range ( ) [ 1 ] - scale . range ( ) [ 0 ] ) / 100 ) ;
}
//TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component
@ -338,17 +342,12 @@ nv.models.axis = function() {
axisLabel . exit ( ) . remove ( ) ;
switch ( axis . orient ( ) ) {
case 'top' :
var w = scale . range ( ) . length == 2 ?
scale . range ( ) [ 1 ] :
( scale . range ( ) [ scale . range ( ) . length - 1 ] + ( scale . range ( ) [ 1 ] - scale . range ( ) [ 0 ] ) ) ;
axisLabel . enter ( ) . append ( 'text' ) . attr ( 'class' , 'nv-axislabel' )
. attr ( 'text-anchor' , 'middle' )
. attr ( 'y' , 0 ) ;
var w = ( scale . range ( ) . length == 2 ) ? scale . range ( ) [ 1 ] : ( scale . range ( ) [ scale . range ( ) . length - 1 ] + ( scale . range ( ) [ 1 ] - scale . range ( ) [ 0 ] ) ) ;
axisLabel
. attr ( 'x' , w / 2 ) ;
. attr ( 'x' , w / 2 ) ;
if ( showMaxMin ) {
var axisMaxMin = wrap . selectAll ( 'g.nv-axisMaxMin' )
. data ( scale . domain ( ) ) ;
@ -372,33 +371,28 @@ nv.models.axis = function() {
}
break ;
case 'bottom' :
var xLabelMargin = 30 ;
var maxTextWidth = 30 ;
if ( rotateLabels % 360 ) {
var xTicks = g . selectAll ( 'g' ) . select ( "text" ) ;
//Calculate the longest xTick width
xTicks . each ( function ( d , i ) {
var width = this . getBBox ( ) . width ;
if ( width > maxTextWidth ) maxTextWidth = width ;
} ) ;
//Convert to radians before calculating sin. Add 30 to margin for healthy padding.
var sin = Math . abs ( Math . sin ( rotateLabels * Math . PI / 180 ) ) ;
var xLabelMargin = ( sin ? sin * maxTextWidth : maxTextWidth ) + 30 ;
//Rotate all xTicks
xTicks
. attr ( 'transform' , 'rotate(' + rotateLabels + ' 0,0)' )
. attr ( 'text-anchor' , rotateLabels % 360 > 0 ? 'start' : 'end' ) ;
}
axisLabel . enter ( ) . append ( 'text' ) . attr ( 'class' , 'nv-axislabel' )
var xLabelMargin = 30 ;
var maxTextWidth = 30 ;
if ( rotateLabels % 360 ) {
var xTicks = g . selectAll ( 'g' ) . select ( "text" ) ;
//Calculate the longest xTick width
xTicks . each ( function ( d , i ) {
var width = this . getBBox ( ) . width ;
if ( width > maxTextWidth ) maxTextWidth = width ;
} ) ;
//Convert to radians before calculating sin. Add 30 to margin for healthy padding.
var sin = Math . abs ( Math . sin ( rotateLabels * Math . PI / 180 ) ) ;
var xLabelMargin = ( sin ? sin * maxTextWidth : maxTextWidth ) + 30 ;
//Rotate all xTicks
xTicks . attr ( 'transform' , function ( d , i , j ) { return 'rotate(' + rotateLabels + ' 0,0)' } )
. attr ( 'text-anchor' , rotateLabels % 360 > 0 ? 'start' : 'end' ) ;
}
axisLabel . enter ( ) . append ( 'text' ) . attr ( 'class' , 'nv-axislabel' )
. attr ( 'text-anchor' , 'middle' )
. attr ( 'y' , xLabelMargin ) ;
var w = ( scale . range ( ) . length == 2 ) ?
scale . range ( ) [ 1 ] :
scale . range ( ) [ scale . range ( ) . length - 1 ] + ( scale . range ( ) [ 1 ] - scale . range ( ) [ 0 ] ) ;
var w = ( scale . range ( ) . length == 2 ) ? scale . range ( ) [ 1 ] : ( scale . range ( ) [ scale . range ( ) . length - 1 ] + ( scale . range ( ) [ 1 ] - scale . range ( ) [ 0 ] ) ) ;
axisLabel
. attr ( 'x' , w / 2 ) ;
. attr ( 'x' , w / 2 ) ;
if ( showMaxMin ) {
var axisMaxMin = wrap . selectAll ( 'g.nv-axisMaxMin' )
. data ( scale . domain ( ) ) ;
@ -542,7 +536,7 @@ nv.models.axis = function() {
}
d3 . rebind ( chart , axis , 'orient' , 'tick s', 'tick Values', 'tickSubdivide' , 'tickSize' , 'tickPadding' , 'tickFormat' ) ;
d3 . rebind ( chart , axis , 'orient' , 'tick Values', 'tickSubdivide' , 'tickSize' , 'tickPadding' , 'tickFormat' ) ;
d3 . rebind ( chart , scale , 'domain' , 'range' , 'rangeBand' , 'rangeBands' ) ; //these are also accessible by chart.scale(), but added common ones directly for ease of use
chart . width = function ( _ ) {
@ -551,6 +545,12 @@ nv.models.axis = function() {
return chart ;
} ;
chart . ticks = function ( _ ) {
if ( ! arguments . length ) return ticks ;
ticks = _ ;
return chart ;
} ;
chart . height = function ( _ ) {
if ( ! arguments . length ) return height ;
height = _ ;
@ -583,9 +583,9 @@ nv.models.axis = function() {
return chart ;
}
chart . rotateYLabel = function ( _ ) {
if ( ! arguments . length ) return rotateYLabel ;
rotateYLabel = _ ;
return chart ;
if ( ! arguments . length ) return rotateYLabel ;
rotateYLabel = _ ;
return chart ;
}
chart . rotateLabels = function ( _ ) {
if ( ! arguments . length ) return rotateLabels ;
@ -593,9 +593,9 @@ nv.models.axis = function() {
return chart ;
}
chart . margin = function ( _ ) {
if ( ! arguments . length ) return margin ;
margin = _ ;
return chart ;
if ( ! arguments . length ) return margin ;
margin = _ ;
return chart ;
}
return chart ;
@ -6978,6 +6978,7 @@ nv.models.scatter = function() {
, sizeRange = null
, singlePoint = false
, dispatch = d3 . dispatch ( 'elementClick' , 'elementMouseover' , 'elementMouseout' )
, useVoronoi = true
;
//============================================================
@ -7009,8 +7010,6 @@ nv.models.scatter = function() {
return series ;
} ) ;
//------------------------------------------------------------
// Setup Scales
@ -7081,11 +7080,11 @@ nv.models.scatter = function() {
g . attr ( 'clip-path' , clipEdge ? 'url(#nv-edge-clip-' + id + ')' : '' ) ;
function updateInteractiveLayer ( ) {
if ( ! interactive ) return false ;
var eventElements ;
var vertices = d3 . merge ( data . map ( function ( group , groupIndex ) {
return group . values
@ -7117,22 +7116,44 @@ nv.models.scatter = function() {
//inject series and point index for reference into voronoi
var voronoi = d3 . geom . voronoi ( vertices ) . map ( function ( d , i ) {
return {
'data' : d ,
'series' : vertices [ i ] [ 2 ] ,
'point' : vertices [ i ] [ 3 ]
}
} ) ;
if ( useVoronoi === true ) {
var voronoi = d3 . geom . voronoi ( vertices ) . map ( function ( d , i ) {
return {
'data' : d ,
'series' : vertices [ i ] [ 2 ] ,
'point' : vertices [ i ] [ 3 ]
}
} ) ;
var pointPaths = wrap . select ( '.nv-point-paths' ) . selectAll ( 'path' )
. data ( voronoi ) ;
pointPaths . enter ( ) . append ( 'path' )
. attr ( 'class' , function ( d , i ) { return 'nv-path-' + i ; } ) ;
pointPaths . exit ( ) . remove ( ) ;
pointPaths
. attr ( 'd' , function ( d ) { return 'M' + d . data . join ( ',' ) + 'Z' ; } )
var pointPaths = wrap . select ( '.nv-point-paths' ) . selectAll ( 'path' )
. data ( voronoi ) ;
pointPaths . enter ( ) . append ( 'path' )
. attr ( 'class' , function ( d , i ) { return 'nv-path-' + i ; } ) ;
pointPaths . exit ( ) . remove ( ) ;
pointPaths
. attr ( 'd' , function ( d ) { return 'M' + d . data . join ( ',' ) + 'Z' ; } ) ;
eventElements = pointPaths ;
} else {
// bring data in form needed for click handlers
var dataWithPoints = vertices . map ( function ( d , i ) {
return {
'data' : d ,
'series' : vertices [ i ] [ 2 ] ,
'point' : vertices [ i ] [ 3 ]
}
} ) ;
// add event handlers to points instead voronoi paths
eventElements = wrap . select ( '.nv-groups' ) . selectAll ( '.nv-group' )
. selectAll ( 'path.nv-point' )
. data ( dataWithPoints )
. style ( 'pointer-events' , 'auto' ) ; // recativate events, disabled by css
}
eventElements
. on ( 'click' , function ( d ) {
var series = data [ d . series ] ,
point = series . values [ d . point ] ;
@ -7332,7 +7353,7 @@ nv.models.scatter = function() {
sizeDomain = _ ;
return chart ;
} ;
chart . sizeRange = function ( _ ) {
if ( ! arguments . length ) return sizeRange ;
sizeRange = _ ;
@ -7381,6 +7402,15 @@ nv.models.scatter = function() {
return chart ;
} ;
chart . useVoronoi = function ( _ ) {
if ( ! arguments . length ) return useVoronoi ;
useVoronoi = _ ;
if ( useVoronoi === false ) {
clipVoronoi = false ;
}
return chart ;
} ;
chart . clipRadius = function ( _ ) {
if ( ! arguments . length ) return clipRadius ;
clipRadius = _ ;
@ -7594,7 +7624,7 @@ nv.models.scatterChart = function() {
xAxis
. scale ( x )
. ticks ( availableWidth / 100 )
. ticks ( xAxis. ticks ( ) ? xAxis . ticks ( ) : availableWidth / 100 )
. tickSize ( - availableHeight , 0 ) ;
g . select ( '.nv-x.nv-axis' )
@ -7604,7 +7634,7 @@ nv.models.scatterChart = function() {
yAxis
. scale ( y )
. ticks ( availableHeight / 36 )
. ticks ( yAxis. ticks ( ) ? yAxis . ticks ( ) : availableHeight / 36 )
. tickSize ( - availableWidth , 0 ) ;
g . select ( '.nv-y.nv-axis' )
@ -7624,8 +7654,8 @@ nv.models.scatterChart = function() {
g . select ( '.nv-distributionX' )
. datum ( data . filter ( function ( d ) { return ! d . disabled } ) )
. call ( distX ) ;
}
}
if ( showDistY ) {
distY
. getData ( scatter . y ( ) )
@ -7785,7 +7815,7 @@ nv.models.scatterChart = function() {
chart . distX = distX ;
chart . distY = distY ;
d3 . rebind ( chart , scatter , 'id' , 'interactive' , 'pointActive' , 'x' , 'y' , 'shape' , 'size' , 'xScale' , 'yScale' , 'zScale' , 'xDomain' , 'yDomain' , 'sizeDomain' , 'sizeRange' , 'forceX' , 'forceY' , 'forceSize' , 'clipVoronoi' , 'clipRadius' );
d3 . rebind ( chart , scatter , 'id' , 'interactive' , 'pointActive' , 'x' , 'y' , 'shape' , 'size' , 'xScale' , 'yScale' , 'zScale' , 'xDomain' , 'yDomain' , 'sizeDomain' , 'sizeRange' , 'forceX' , 'forceY' , 'forceSize' , 'clipVoronoi' , 'clipRadius' , 'useVoronoi' );
chart . margin = function ( _ ) {
if ( ! arguments . length ) return margin ;