@ -2,7 +2,7 @@
'use strict' ;
var c3 = {
version : "0.1.29 "
version : "0.1.30 "
} ;
var CLASS = {
@ -113,7 +113,9 @@
_ _zoom _privileged = getConfig ( [ 'zoom' , 'privileged' ] , false ) ;
var _ _onenter = getConfig ( [ 'onenter' ] , function ( ) { } ) ,
_ _onleave = getConfig ( [ 'onleave' ] , function ( ) { } ) ;
_ _onleave = getConfig ( [ 'onleave' ] , function ( ) { } ) ,
_ _onresize = getConfig ( [ 'onresize' ] , function ( ) { } ) ,
_ _onresized = getConfig ( [ 'onresized' ] , function ( ) { } ) ;
var _ _transition _duration = getConfig ( [ 'transition' , 'duration' ] , 350 ) ;
@ -163,13 +165,15 @@
// axis
var _ _axis _rotated = getConfig ( [ 'axis' , 'rotated' ] , false ) ,
_ _axis _x _type = getConfig ( [ 'axis' , 'x' , 'type' ] , 'indexed' ) ,
_ _axis _x _localtime = getConfig ( [ 'axis' , 'x' , 'localtime' ] , false ) ,
_ _axis _x _categories = getConfig ( [ 'axis' , 'x' , 'categories' ] , [ ] ) ,
_ _axis _x _tick _centered = getConfig ( [ 'axis' , 'x' , 'tick' , 'centered' ] , false ) ,
_ _axis _x _tick _format = getConfig ( [ 'axis' , 'x' , 'tick' , 'format' ] ) ,
_ _axis _x _tick _culling = getConfig ( [ 'axis' , 'x' , 'tick' , 'culling' ] , { } ) ,
_ _axis _x _tick _culling _max = getConfig ( [ 'axis' , 'x' , 'tick' , 'culling' , 'max' ] , _ _axis _x _type === 'categorized' ? Infinity : 10 ) ,
_ _axis _x _tick _culling _max = getConfig ( [ 'axis' , 'x' , 'tick' , 'culling' , 'max' ] , 10 ) ,
_ _axis _x _tick _count = getConfig ( [ 'axis' , 'x' , 'tick' , 'count' ] ) ,
_ _axis _x _tick _fit = getConfig ( [ 'axis' , 'x' , 'tick' , 'fit' ] , false ) ,
_ _axis _x _tick _values = getConfig ( [ 'axis' , 'x' , 'tick' , 'values' ] , [ ] ) ,
_ _axis _x _max = getConfig ( [ 'axis' , 'x' , 'max' ] ) ,
_ _axis _x _min = getConfig ( [ 'axis' , 'x' , 'min' ] ) ,
_ _axis _x _default = getConfig ( [ 'axis' , 'x' , 'default' ] ) ,
@ -211,6 +215,8 @@
_ _point _focus _expand _r = getConfig ( [ 'point' , 'focus' , 'expand' , 'r' ] , _ _point _focus _expand _enabled ? 4 : _ _point _r ) ,
_ _point _select _r = getConfig ( [ 'point' , 'focus' , 'select' , 'r' ] , 8 ) ;
var _ _line _connect _null = getConfig ( [ 'line' , 'connect_null' ] , false ) ;
// bar
var _ _bar _width = getConfig ( [ 'bar' , 'width' ] ) ,
_ _bar _width _ratio = getConfig ( [ 'bar' , 'width' , 'ratio' ] , 0.6 ) ;
@ -269,8 +275,8 @@
clipIdForXAxis = clipId + '-xaxis' ,
clipIdForYAxis = clipId + '-yaxis' ,
clipPath = getClipPath ( clipId ) ,
clipPathForXAxis = getClipPath ( clipPath ForXAxis ) ,
clipPathForYAxis = getClipPath ( clipPath ForYAxis ) ;
clipPathForXAxis = getClipPath ( clipId ForXAxis ) ,
clipPathForYAxis = getClipPath ( clipId ForYAxis ) ;
var isTimeSeries = ( _ _axis _x _type === 'timeseries' ) ,
isCategorized = ( _ _axis _x _type === 'categorized' ) ,
@ -281,16 +287,17 @@
var defaultColorPattern = [ '#1f77b4' , '#ff7f0e' , '#2ca02c' , '#d62728' , '#9467bd' , '#8c564b' , '#e377c2' , '#7f7f7f' , '#bcbd22' , '#17becf' ] , //same as d3.scale.category10()
color = generateColor ( _ _data _colors , notEmpty ( _ _color _pattern ) ? _ _color _pattern : defaultColorPattern , _ _data _color ) ;
var defaultTimeFormat = ( function ( ) {
var xTimeFormat = _ _axis _x _localtime ? d3 . time . format : d3 . time . format . utc ,
defaultTimeFormat = ( function ( ) {
var formats = [
[ d3 . time . f ormat( "%Y/%-m/%-d" ) , function ( ) { return true ; } ] ,
[ d3 . time . f ormat( "%-m/%-d" ) , function ( d ) { return d . getMonth ( ) ; } ] ,
[ d3 . time . f ormat( "%-m/%-d" ) , function ( d ) { return d . getDate ( ) !== 1 ; } ] ,
[ d3 . time . f ormat( "%-m/%-d" ) , function ( d ) { return d . getDay ( ) && d . getDate ( ) !== 1 ; } ] ,
[ d3 . time . f ormat( "%I %p" ) , function ( d ) { return d . getHours ( ) ; } ] ,
[ d3 . time . f ormat( "%I:%M" ) , function ( d ) { return d . getMinutes ( ) ; } ] ,
[ d3 . time . f ormat( ":%S" ) , function ( d ) { return d . getSeconds ( ) ; } ] ,
[ d3 . time . f ormat( ".%L" ) , function ( d ) { return d . getMilliseconds ( ) ; } ]
[ xTimeF ormat( "%Y/%-m/%-d" ) , function ( ) { return true ; } ] ,
[ xTimeF ormat( "%-m/%-d" ) , function ( d ) { return d . getMonth ( ) ; } ] ,
[ xTimeF ormat( "%-m/%-d" ) , function ( d ) { return d . getDate ( ) !== 1 ; } ] ,
[ xTimeF ormat( "%-m/%-d" ) , function ( d ) { return d . getDay ( ) && d . getDate ( ) !== 1 ; } ] ,
[ xTimeF ormat( "%I %p" ) , function ( d ) { return d . getHours ( ) ; } ] ,
[ xTimeF ormat( "%I:%M" ) , function ( d ) { return d . getMinutes ( ) ; } ] ,
[ xTimeF ormat( ":%S" ) , function ( d ) { return d . getSeconds ( ) ; } ] ,
[ xTimeF ormat( ".%L" ) , function ( d ) { return d . getMilliseconds ( ) ; } ]
] ;
return function ( date ) {
var i = formats . length - 1 , f = formats [ i ] ;
@ -615,6 +622,9 @@
axis . tickFormat ( tickFormat ) ;
if ( isCategorized ) {
axis . tickCentered ( _ _axis _x _tick _centered ) ;
if ( isEmpty ( _ _axis _x _tick _culling ) ) {
_ _axis _x _tick _culling = false ;
}
} else {
axis . tickOffset = function ( ) {
var base = _ _axis _rotated ? height : width ;
@ -641,7 +651,7 @@
if ( typeof _ _axis _x _tick _format === 'function' ) {
format = _ _axis _x _tick _format ;
} else if ( isTimeSeries ) {
format = function ( date ) { return d3 . time . f ormat( _ _axis _x _tick _format ) ( date ) ; } ;
format = function ( date ) { return xTimeF ormat( _ _axis _x _tick _format ) ( date ) ; } ;
}
}
return format ;
@ -785,7 +795,7 @@
function getMaxTickWidth ( id ) {
var maxWidth = 0 , axisClass = id === 'x' ? CLASS . axisX : id === 'y' ? CLASS . axisY : CLASS . axisY2 ;
d3 . selectAll ( '.' + axisClass + ' .tick text' ) . each ( function ( ) {
var box = this . getBBox ( ) ;
var box = this . getBoundingClientRect ( ) ;
if ( maxWidth < box . width ) { maxWidth = box . width ; }
} ) ;
return maxWidth < 20 ? 20 : maxWidth ;
@ -824,10 +834,6 @@
}
return ticks ;
}
function shouldShowTickText ( ticks , i ) {
var length = ticks . length - 1 ;
return length <= tickTextNum || i % Math . ceil ( length / tickTextNum ) === 0 ;
}
function category ( i ) {
return i < categories . length ? categories [ i ] : i ;
}
@ -870,7 +876,7 @@
lineUpdate . attr ( "x1" , tickX ) . attr ( "x2" , tickX ) . attr ( "y2" , tickMajorSize ) ;
textUpdate . attr ( "x" , 0 ) . attr ( "y" , Math . max ( tickMajorSize , 0 ) + tickPadding ) ;
text . attr ( "dy" , ".71em" ) . style ( "text-anchor" , "middle" ) ;
text . text ( function ( i ) { return shouldShowTickText ( ticks , i ) ? formattedCategory ( i ) : "" ; } ) ;
text . text ( formattedCategory ) ;
pathUpdate . attr ( "d" , "M" + range [ 0 ] + "," + tickEndSize + "V0H" + range [ 1 ] + "V" + tickEndSize ) ;
break ;
}
@ -895,7 +901,7 @@
lineUpdate . attr ( "x2" , - tickMajorSize ) . attr ( "y2" , 0 ) ;
textUpdate . attr ( "x" , - ( Math . max ( tickMajorSize , 0 ) + tickPadding ) ) . attr ( "y" , tickOffset ) ;
text . attr ( "dy" , ".32em" ) . style ( "text-anchor" , "end" ) ;
text . text ( function ( i ) { return shouldShowTickText ( ticks , i ) ? formattedCategory ( i ) : "" ; } ) ;
text . text ( formattedCategory ) ;
pathUpdate . attr ( "d" , "M" + - tickEndSize + "," + range [ 0 ] + "H0V" + range [ 1 ] + "H" + - tickEndSize ) ;
break ;
}
@ -1216,8 +1222,13 @@
var xDomain = [ getXDomainMin ( targets ) , getXDomainMax ( targets ) ] ,
firstX = xDomain [ 0 ] , lastX = xDomain [ 1 ] ,
padding = getXDomainPadding ( targets , xDomain ) ,
min = isTimeSeries ? new Date ( firstX . getTime ( ) - padding ) : firstX - padding ,
min = 0 , max = 0 ;
if ( firstX || firstX === 0 ) {
min = isTimeSeries ? new Date ( firstX . getTime ( ) - padding ) : firstX - padding ;
}
if ( lastX || lastX === 0 ) {
max = isTimeSeries ? new Date ( lastX . getTime ( ) + padding ) : lastX + padding ;
}
return [ min , max ] ;
}
function diffDomain ( d ) {
@ -1520,6 +1531,7 @@
tickValues . push ( end ) ;
}
}
if ( ! isTimeSeries ) { tickValues = tickValues . sort ( function ( a , b ) { return a - b ; } ) ; }
return tickValues ;
}
function addHiddenTargetIds ( targetIds ) {
@ -1628,7 +1640,7 @@
. data ( [ min , max ] )
. enter ( ) . append ( 'text' )
. text ( function ( d ) { return d ; } )
. each ( function ( d , i ) { var box = this . getBBox ( ) ; widths [ i ] = box . width * paddingCoef ; } )
. each ( function ( d , i ) { widths [ i ] = this . getBoundingClientRect ( ) . width * paddingCoef ; } )
. remove ( ) ;
return widths ;
}
@ -1999,13 +2011,11 @@
function parseDate ( date ) {
var parsedDate ;
if ( ! date ) { throw Error ( date + " can not be parsed as d3.time with format " + _ _data _x _format + ". Maybe 'x' of this data is not defined. See data.x or data.xs option." ) ; }
try {
parsedDate = _ _data _x _format ? d3 . time . format ( _ _data _x _format ) . parse ( date ) : new Date ( date ) ;
} catch ( e ) {
parsedDate = undefined ;
window . console . error ( "Failed to parse x '" + date + "' to Date with format " + _ _data _x _format ) ;
}
if ( ! parsedDate ) { window . console . error ( "Failed to parse x '" + date + "' to Date with format " + _ _data _x _format ) ; }
return parsedDate ;
}
@ -2017,8 +2027,9 @@
return Math . sqrt ( Math . pow ( cx - mouse [ 0 ] , 2 ) + Math . pow ( cy - mouse [ 1 ] , 2 ) ) < _r ;
}
function isWithinBar ( _this ) {
var mouse = d3 . mouse ( _this ) , box = _this . getBBox ( ) ;
var x = box . x , y = box . y , w = box . width , h = box . height , offset = 2 ;
var mouse = d3 . mouse ( _this ) , box = _this . getBoundingClientRect ( ) ,
seg0 = _this . pathSegList . getItem ( 0 ) , seg1 = _this . pathSegList . getItem ( 1 ) ;
var x = seg0 . x , y = Math . min ( seg0 . y , seg1 . y ) , w = box . width , h = box . height , offset = 2 ;
var sx = x - offset , ex = x + w + offset , sy = y + h + offset , ey = y - offset ;
return sx < mouse [ 0 ] && mouse [ 0 ] < ex && ey < mouse [ 1 ] && mouse [ 1 ] < sy ;
}
@ -2134,14 +2145,15 @@
var line = d3 . svg . line ( )
. x ( _ _axis _rotated ? function ( d ) { return getYScale ( d . id ) ( d . value ) ; } : xx )
. y ( _ _axis _rotated ? xx : function ( d ) { return getYScale ( d . id ) ( d . value ) ; } ) ;
if ( ! _ _line _connect _null ) { line = line . defined ( function ( d ) { return d . value != null ; } ) ; }
return function ( d ) {
var data = filterRemoveNull ( d . values ) , x0 , y0 ;
var data = _ _line _connect _null ? filterRemoveNull ( d . values ) : d . values , x0 , y0 ;
if ( isLineType ( d ) ) {
isSplineType ( d ) ? line . interpolate ( "cardinal" ) : line . interpolate ( "linear" ) ;
return _ _data _regions [ d . id ] ? lineWithRegions ( data , x , getYScale ( d . id ) , _ _data _regions [ d . id ] ) : line ( data ) ;
} else {
x0 = x ( data [ 0 ] . x ) ;
y0 = getYScale ( d . id ) ( data [ 0 ] . value ) ;
x0 = data [ 0 ] ? x ( data [ 0 ] . x ) : 0 ;
y0 = data [ 0 ] ? getYScale ( d . id ) ( data [ 0 ] . value ) : 0 ;
return _ _axis _rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0 ;
}
} ;
@ -2212,7 +2224,7 @@
}
}
function getYForText ( points , d , textElement ) {
var box = textElement . getBBox ( ) ;
var box = textElement . getBoundingClientRect ( ) ;
if ( _ _axis _rotated ) {
return ( points [ 0 ] [ 0 ] + points [ 2 ] [ 0 ] + box . height * 0.6 ) / 2 ;
} else {
@ -2646,9 +2658,11 @@
window . onresize = generateResize ( ) ;
}
if ( window . onresize . add ) {
window . onresize . add ( _ _onresize ) ;
window . onresize . add ( function ( ) {
updateAndRedraw ( { withLegend : true , withTransition : false , withTransitionForTransform : false } ) ;
} ) ;
window . onresize . add ( _ _onresized ) ;
}
}
@ -2995,7 +3009,7 @@
// update axis tick values according to options, except for scatter plot
if ( ! hasScatterType ( targetsToShow ) ) { // TODO: fix this
tickValues = generateTickValues ( mapTargetsToUniqueXs ( targetsToShow ) ) . sort ( ) ;
tickValues = _ _axis _x _tick _values ? _ _axis _x _tick _values : generateTickValues ( mapTargetsToUniqueXs ( targetsToShow ) ) ;
xAxis . tickValues ( tickValues ) ;
subXAxis . tickValues ( tickValues ) ;
}
@ -3016,17 +3030,23 @@
main . select ( '.' + CLASS . axisY2 ) . style ( "opacity" , hideAxis ? 0 : 1 ) . transition ( ) . duration ( durationForAxis ) . call ( yAxis2 ) ;
// show/hide if manual culling needed
if ( withUpdateXDomain && _ _axis _x _tick _culling && tickValues ) {
if ( withUpdateXDomain ) {
if ( _ _axis _x _tick _culling && tickValues ) {
for ( i = 1 ; i < tickValues . length ; i ++ ) {
if ( tickValues . length / i < _ _axis _x _tick _culling _max ) {
intervalForCulling = i ;
break ;
}
}
d3 . selectAll ( '.' + CLASS . axisX + ' .tick' ) . sort ( function ( e1 , e2 ) { return e1 - e2 ; } ) ;
d3 . selectAll ( '.' + CLASS . axisX + ' .tick text' ) . each ( function ( e , i ) {
d3 . select ( this ) . style ( 'display' , i % intervalForCulling ? 'none' : 'block' ) ;
d3 . selectAll ( '.' + CLASS . axisX + ' .tick text' ) . each ( function ( e ) {
var index = tickValues . indexOf ( e ) ;
if ( index >= 0 ) {
d3 . select ( this ) . style ( 'display' , index % intervalForCulling ? 'none' : 'block' ) ;
}
} ) ;
} else {
d3 . selectAll ( '.' + CLASS . axisX + ' .tick text' ) . style ( 'display' , 'block' ) ;
}
}
// setup drawer - MEMO: these must be called after axis updated
@ -3671,14 +3691,16 @@
/*-- Draw Legend --*/
function opacityForLegend ( id ) {
return d3 . select ( selectorLegend ( id ) ) . classed ( CLASS . legendItemHidden ) ? 0.5 : 1 ;
var item = legend . select ( selectorLegend ( id ) ) ;
item . style ( 'opacity' , null ) ; // MEMO: remove to get opacity by css
return item . classed ( CLASS . legendItemHidden ) ? item . style ( 'opacity' ) : 1 ;
}
function toggleFocusLegend ( id , focus ) {
var legendItem = legend . selectAll ( '.' + CLASS . legendItem ) ,
var items = legend . selectAll ( '.' + CLASS . legendItem ) . filter ( function ( ) { return ! d3 . select ( this ) . classed ( CLASS . legendItemHidden ) ; } ) ,
isTarget = function ( d ) { return ( ! id || d === id ) ; } ,
notTarget = function ( d ) { return ! isTarget ( d ) ; } ;
legendItem . filter ( notTarget ) . transition ( ) . duration ( 100 ) . style ( 'opacity' , focus ? 0.3 : opacityForLegend ) ;
legendItem . filter ( isTarget ) . transition ( ) . duration ( 100 ) . style ( 'opacity' , focus ? opacityForLegend : 0.3 ) ;
items . filter ( notTarget ) . transition ( ) . duration ( 100 ) . style ( 'opacity' , focus ? 0.3 : opacityForLegend ) ;
items . filter ( isTarget ) . transition ( ) . duration ( 100 ) . style ( 'opacity' , focus ? opacityForLegend : 0.3 ) ;
}
function focusLegend ( id ) {
toggleFocusLegend ( id , true ) ;
@ -3719,7 +3741,7 @@
withTransformAll = isDefined ( options . withTransformAll ) ? options . withTransformAll : true ;
function updatePositions ( textElement , id , reset ) {
var box = textElement . getBBox ( ) ,
var box = textElement . getBoundingClientRect ( ) ,
itemWidth = Math . ceil ( ( box . width + paddingRight ) / 10 ) * 10 ,
itemHeight = Math . ceil ( ( box . height + paddingTop ) / 10 ) * 10 ,
itemLength = isLegendRight ? itemHeight : itemWidth ,
@ -3942,9 +3964,7 @@
showLegend ( targetIds ) ;
} else {
legend . selectAll ( selectorLegends ( targetIds ) )
. classed ( CLASS . legendItemHidden , false )
. transition ( )
. style ( 'opacity' , 1 ) ;
. classed ( CLASS . legendItemHidden , false ) ;
}
redraw ( { withUpdateOrgXDomain : true , withUpdateXDomain : true , withTransitionForHorizontalAxis : false } ) ;
@ -3963,9 +3983,7 @@
hideLegend ( targetIds ) ;
} else {
legend . selectAll ( selectorLegends ( targetIds ) )
. classed ( CLASS . legendItemHidden , true )
. transition ( )
. style ( 'opacity' , 0.5 ) ;
. classed ( CLASS . legendItemHidden , true ) ;
}
redraw ( { withUpdateOrgXDomain : true , withUpdateXDomain : true , withTransitionForHorizontalAxis : false } ) ;
@ -4265,7 +4283,19 @@
/*-- Load data and init chart with defined functions --*/
if ( 'url' in config . data ) {
d3 . csv ( config . data . url , function ( error , data ) { init ( data ) ; } ) ;
d3 . xhr ( config . data . url , function ( error , data ) {
// TODO: other mine/type
var rows = d3 . csv . parseRows ( data . response ) , d ;
if ( rows . length === 1 ) {
d = [ { } ] ;
rows [ 0 ] . forEach ( function ( id ) {
d [ 0 ] [ id ] = null ;
} ) ;
} else {
d = d3 . csv . parse ( data . response ) ;
}
init ( d ) ;
} ) ;
}
else if ( 'rows' in config . data ) {
init ( convertRowsToData ( config . data . rows ) ) ;