@ -1,6 +1,5 @@
( function ( window ) {
// TODO: Dicide name..
window . c3 = { } ;
/ *
@ -9,15 +8,15 @@
c3 . generate = function ( config ) {
var c3 = { data : { } } ,
_ cache = { } ;
cache = { } ;
/*-- Handle Config --*/
var _checkConfig = function ( key , message ) {
function checkConfig ( key , message ) {
if ( ! ( key in config ) ) throw Error ( message ) ;
} ;
var _getConfig = function ( keys , defaultValue ) {
function getConfig ( keys , defaultValue ) {
var target = config ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( ! ( keys [ i ] in target ) ) return defaultValue ;
@ -27,72 +26,72 @@
} ;
// bindto - id to bind the chart
_ checkConfig( 'bindto' , 'bindto is required in config' ) ;
checkConfig ( 'bindto' , 'bindto is required in config' ) ;
var _ _size _width = _ getConfig( [ 'size' , 'width' ] , 640 ) ,
_ _size _height = _ getConfig( [ 'size' , 'height' ] , 480 ) ;
var _ _size _width = getConfig ( [ 'size' , 'width' ] , 640 ) ,
_ _size _height = getConfig ( [ 'size' , 'height' ] , 480 ) ;
// data - data configuration
_ checkConfig( 'data' , 'data is required in config' ) ;
var _ _data _x = _ getConfig( [ 'data' , 'x' ] , 'x' ) ,
_ _data _x _format = _ getConfig( [ 'data' , 'x_format' ] , '%Y-%m-%d' ) ,
_ _data _id _converter = _ getConfig( [ 'data' , 'id_converter' ] , function ( id ) { return id ; } ) ,
_ _data _names = _ getConfig( [ 'data' , 'names' ] , { } ) ,
_ _data _types = _ getConfig( [ 'data' , 'types' ] , { } ) ,
_ _data _regions = _ getConfig( [ 'data' , 'regions' ] , { } ) ,
_ _data _colors = _ getConfig( [ 'data' , 'colors' ] , { } ) ,
_ _data _selection _enabled = _ getConfig( [ 'data' , 'selection' , 'enabled' ] , false ) ;
_ _data _selection _grouped = _ getConfig( [ 'data' , 'selection' , 'grouped' ] , false ) ;
_ _data _selection _isselectable = _ getConfig( [ 'data' , 'selection' , 'isselectable' ] , function ( d ) { return true ; } ) ;
checkConfig ( 'data' , 'data is required in config' ) ;
var _ _data _x = getConfig ( [ 'data' , 'x' ] , 'x' ) ,
_ _data _x _format = getConfig ( [ 'data' , 'x_format' ] , '%Y-%m-%d' ) ,
_ _data _id _converter = getConfig ( [ 'data' , 'id_converter' ] , function ( id ) { return id ; } ) ,
_ _data _names = getConfig ( [ 'data' , 'names' ] , { } ) ,
_ _data _types = getConfig ( [ 'data' , 'types' ] , { } ) ,
_ _data _regions = getConfig ( [ 'data' , 'regions' ] , { } ) ,
_ _data _colors = getConfig ( [ 'data' , 'colors' ] , { } ) ,
_ _data _selection _enabled = getConfig ( [ 'data' , 'selection' , 'enabled' ] , false ) ;
_ _data _selection _grouped = getConfig ( [ 'data' , 'selection' , 'grouped' ] , false ) ;
_ _data _selection _isselectable = getConfig ( [ 'data' , 'selection' , 'isselectable' ] , function ( d ) { return true ; } ) ;
// subchart
var _ _subchart _show = _ getConfig( [ 'subchart' , 'show' ] , true ) ,
_ _subchart _size _height = _ _subchart _show ? _ getConfig( [ 'subchart' , 'size' , 'height' ] , 60 ) : 0 ,
_ _subchart _default = _ getConfig( [ 'subchart' , 'default' ] , null ) ;
var _ _subchart _show = getConfig ( [ 'subchart' , 'show' ] , true ) ,
_ _subchart _size _height = _ _subchart _show ? getConfig ( [ 'subchart' , 'size' , 'height' ] , 60 ) : 0 ,
_ _subchart _default = getConfig ( [ 'subchart' , 'default' ] , null ) ;
// color
var _ _color _pattern = _ getConfig( [ 'color' , 'pattern' ] , null ) ;
var _ _color _pattern = getConfig ( [ 'color' , 'pattern' ] , null ) ;
// legend
var _ _legend _show = _ getConfig( [ 'legend' , 'show' ] , true ) ,
_ _legend _item _width = _ getConfig( [ 'legend' , 'item' , 'width' ] , 80 ) , // TODO: auto
_ _legend _item _onclick = _ getConfig( [ 'legend' , 'item' , 'onclick' ] , function ( ) { } ) ;
var _ _legend _show = getConfig ( [ 'legend' , 'show' ] , true ) ,
_ _legend _item _width = getConfig ( [ 'legend' , 'item' , 'width' ] , 80 ) , // TODO: auto
_ _legend _item _onclick = getConfig ( [ 'legend' , 'item' , 'onclick' ] , function ( ) { } ) ;
// axis
var _ _axis _x _type = _ getConfig( [ 'axis' , 'x' , 'type' ] , 'indexed' ) ,
_ _axis _x _categories = _ getConfig( [ 'axis' , 'x' , 'categories' ] , [ 'hoge' ] ) ,
_ _axis _x _tick _centered = _ getConfig( [ 'axis' , 'x' , 'tick' , 'centered' ] , false ) ,
_ _axis _y _max = _ getConfig( [ 'axis' , 'y' , 'max' ] , null ) ,
_ _axis _y _min = _ getConfig( [ 'axis' , 'y' , 'min' ] , null ) ,
_ _axis _y _center = _ getConfig( [ 'axis' , 'y' , 'center' ] , null ) ,
_ _axis _y _text = _ getConfig( [ 'axis' , 'y' , 'text' ] , null ) ,
_ _axis _y _rescale = _ getConfig( [ 'axis' , 'y' , 'rescale' ] , true ) ;
var _ _axis _x _type = getConfig ( [ 'axis' , 'x' , 'type' ] , 'indexed' ) ,
_ _axis _x _categories = getConfig ( [ 'axis' , 'x' , 'categories' ] , [ 'hoge' ] ) ,
_ _axis _x _tick _centered = getConfig ( [ 'axis' , 'x' , 'tick' , 'centered' ] , false ) ,
_ _axis _y _max = getConfig ( [ 'axis' , 'y' , 'max' ] , null ) ,
_ _axis _y _min = getConfig ( [ 'axis' , 'y' , 'min' ] , null ) ,
_ _axis _y _center = getConfig ( [ 'axis' , 'y' , 'center' ] , null ) ,
_ _axis _y _text = getConfig ( [ 'axis' , 'y' , 'text' ] , null ) ,
_ _axis _y _rescale = getConfig ( [ 'axis' , 'y' , 'rescale' ] , true ) ;
// grid
var _ _grid _x _show = _ getConfig( [ 'grid' , 'x' , 'show' ] , false ) ,
_ _grid _x _type = _ getConfig( [ 'grid' , 'x' , 'type' ] , 'tick' ) ,
_ _grid _x _lines = _ getConfig( [ 'grid' , 'x' , 'lines' ] , null ) ,
_ _grid _y _show = _ getConfig( [ 'grid' , 'y' , 'show' ] , false ) ,
_ _grid _y _type = _ getConfig( [ 'grid' , 'y' , 'type' ] , 'tick' ) ,
_ _grid _y _lines = _ getConfig( [ 'grid' , 'y' , 'lines' ] , null ) ;
var _ _grid _x _show = getConfig ( [ 'grid' , 'x' , 'show' ] , false ) ,
_ _grid _x _type = getConfig ( [ 'grid' , 'x' , 'type' ] , 'tick' ) ,
_ _grid _x _lines = getConfig ( [ 'grid' , 'x' , 'lines' ] , null ) ,
_ _grid _y _show = getConfig ( [ 'grid' , 'y' , 'show' ] , false ) ,
_ _grid _y _type = getConfig ( [ 'grid' , 'y' , 'type' ] , 'tick' ) ,
_ _grid _y _lines = getConfig ( [ 'grid' , 'y' , 'lines' ] , null ) ;
// point - point of each data
var _ _point _show = _ getConfig( [ 'point' , 'show' ] , false ) ,
_ _point _r = _ _point _show ? _ getConfig( [ 'point' , 'r' ] , 2.5 ) : 0 ,
_ _point _focus _line _enabled = _ getConfig( [ 'point' , 'focus' , 'line' , 'enabled' ] , false ) ,
_ _point _focus _expand _enabled = _ getConfig( [ 'point' , 'focus' , 'expand' , 'enabled' ] , _ _point _show ) ,
_ _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 ) ,
_ _point _onclick = _ getConfig( [ 'point' , 'onclick' ] , function ( ) { } ) ,
_ _point _onselected = _ getConfig( [ 'point' , 'onselected' ] , function ( ) { } ) ,
_ _point _onunselected = _ getConfig( [ 'point' , 'onunselected' ] , function ( ) { } ) ;
var _ _point _show = getConfig ( [ 'point' , 'show' ] , false ) ,
_ _point _r = _ _point _show ? getConfig ( [ 'point' , 'r' ] , 2.5 ) : 0 ,
_ _point _focus _line _enabled = getConfig ( [ 'point' , 'focus' , 'line' , 'enabled' ] , false ) ,
_ _point _focus _expand _enabled = getConfig ( [ 'point' , 'focus' , 'expand' , 'enabled' ] , _ _point _show ) ,
_ _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 ) ,
_ _point _onclick = getConfig ( [ 'point' , 'onclick' ] , function ( ) { } ) ,
_ _point _onselected = getConfig ( [ 'point' , 'onselected' ] , function ( ) { } ) ,
_ _point _onunselected = getConfig ( [ 'point' , 'onunselected' ] , function ( ) { } ) ;
// region - region to change style
var _ _regions = _ getConfig( [ 'regions' ] , null ) ;
var _ _regions = getConfig ( [ 'regions' ] , null ) ;
// tooltip - show when mouseover on each data
var _ _tooltip _contents = _ getConfig( [ 'tooltip' , 'contents' ] , function ( d ) {
var _ _tooltip _contents = getConfig ( [ 'tooltip' , 'contents' ] , function ( d ) {
var date = isTimeSeries ? d [ 0 ] . x . getFullYear ( ) + '.' + ( d [ 0 ] . x . getMonth ( ) + 1 ) + '.' + d [ 0 ] . x . getDate ( ) : isCategorized ? category ( d [ 0 ] . x ) : d [ 0 ] . x ,
text = "<table class='tooltip'><tr><th colspan='2'>" + date + "</th></tr>" ;
for ( var i = 0 ; i < d . length ; i ++ ) {
@ -102,7 +101,17 @@
return text + "</table>" ;
} ) ;
/*-- Define TimeFormat --*/
/*-- Set Variables --*/
var clipId = config . bindto . replace ( '#' , '' ) + '-clip' ,
clipPath = "url(#" + clipId + ")" ;
var isTimeSeries = ( _ _axis _x _type === 'timeseries' ) ,
isCategorized = ( _ _axis _x _type === 'categorized' ) ;
var dragStart = null , dragging = false ;
var legendHeight = _ _legend _show ? 40 : 0 ;
var customTimeFormat = timeFormat ( [
[ d3 . time . format ( "%Y/%-m/%-d" ) , function ( ) { return true ; } ] ,
@ -122,17 +131,7 @@
} ;
}
/*-- Set Variables --*/
var clipId = config . bindto . replace ( '#' , '' ) + '-clip' ,
clipPath = "url(#" + clipId + ")" ;
var isTimeSeries = ( _ _axis _x _type === 'timeseries' ) ,
isCategorized = ( _ _axis _x _type === 'categorized' ) ;
var dragStart = null , dragging = false ;
var legendHeight = _ _legend _show ? 40 : 0 ;
/*-- Set Chart Params --*/
var margin _bottom = 20 + _ _subchart _size _height + legendHeight ,
margin2 _top = _ _size _height - _ _subchart _size _height - legendHeight ,
@ -217,8 +216,9 @@
}
// Define color
var color = _ generateColor( _ _data _colors , _ _color _pattern ) ;
var color = generateColor ( _ _data _colors , _ _color _pattern ) ;
// Define svgs
var svg = d3 . select ( config . bindto ) . append ( "svg" )
. attr ( "width" , width + margin . left + margin . right )
. attr ( "height" , height + margin . top + margin . bottom ) ;
@ -239,21 +239,21 @@
. attr ( "width" , width + 2 )
. attr ( "height" , 40 ) ;
// Define regions
var main = svg . append ( "g" )
. attr ( "transform" , "translate(" + margin . left + "," + margin . top + ")" ) ;
var context = null ;
if ( _ _subchart _show ) {
context = svg . append ( "g" )
. attr ( "transform" , "translate(" + margin2 . left + "," + margin2 . top + ")" ) ;
}
var legend = null ;
if ( _ _legend _show ) {
legend = svg . append ( "g" )
. attr ( "transform" , "translate(" + margin3 . left + "," + margin3 . top + ")" ) ;
}
// Define tooltip
var tooltip = d3 . select ( config . bindto )
. style ( "position" , "relative" )
. append ( "div" )
@ -264,15 +264,17 @@
/*-- Define Functions --*/
var _getYDomainMin = function ( targets ) {
//-- Domain --//
function getYDomainMin ( targets ) {
return ( _ _axis _y _min !== null ) ? _ _axis _y _min : d3 . min ( targets , function ( t ) { return d3 . min ( t . values , function ( v ) { return v . value ; } ) ; } ) ;
} ;
var _getYDomainMax = function ( targets ) {
function getYDomainMax ( targets ) {
return ( _ _axis _y _max !== null ) ? _ _axis _y _max : d3 . max ( targets , function ( t ) { return d3 . max ( t . values , function ( v ) { return v . value ; } ) ; } ) ;
} ;
var _getYDomain = functio n ( targets ) {
var yDomainMin = _ getYDomainMin( targets ) ,
yDomainMax = _ getYDomainMax( targets ) ,
function getYDomai n ( targets ) {
var yDomainMin = getYDomainMin ( targets ) ,
yDomainMax = getYDomainMax ( targets ) ,
padding = Math . abs ( yDomainMax - yDomainMin ) * 0.1 ;
if ( _ _axis _y _center !== null ) {
yDomainAbs = Math . max ( Math . abs ( yDomainMin ) , Math . abs ( yDomainMax ) ) ;
@ -281,25 +283,34 @@
}
return [ yDomainMin - padding , yDomainMax + padding ] ;
} ;
function getXDomainRatio ( ) {
if ( brush . empty ( ) ) return 1 ;
var domain = x2 . domain ( ) , extent = brush . extent ( ) ;
return ( domain [ 1 ] - domain [ 0 ] ) / ( extent [ 1 ] - extent [ 0 ] ) ;
}
var _hasCaches = function ( ids ) {
//-- Cache --//
function hasCaches ( ids ) {
for ( var i = 0 ; i < ids . length ; i ++ ) {
if ( ! ( ids [ i ] in _cache ) ) return false ;
if ( ! ( ids [ i ] in cache ) ) return false ;
}
return true ;
}
var _addCache = function ( id , target ) {
_ cache[ id ] = target ;
function addCache ( id , target ) {
cache [ id ] = target ;
}
var _getCaches = function ( ids ) {
function getCaches ( ids ) {
var targets = [ ] ;
for ( var i = 0 ; i < ids . length ; i ++ ) {
if ( ids [ i ] in _ cache) targets . push ( _ cache[ ids [ i ] ] ) ;
if ( ids [ i ] in cache ) targets . push ( cache [ ids [ i ] ] ) ;
}
return targets ;
}
var _convertRowsToData = function ( rows ) {
//-- Data --//
function convertRowsToData ( rows ) {
var keys = rows [ 0 ] ,
new _row = { } ,
new _rows = [ ] ;
@ -312,8 +323,7 @@
}
return new _rows ;
} ;
var _convertColumnsToData = function ( columns ) {
function convertColumnsToData ( columns ) {
var new _rows = [ ] ;
for ( var i = 0 ; i < columns . length ; i ++ ) {
var key = columns [ i ] [ 0 ] ;
@ -326,8 +336,7 @@
}
return new _rows ;
} ;
var _convertDataToTargets = function ( data ) {
function convertDataToTargets ( data ) {
var ids = d3 . keys ( data [ 0 ] ) . filter ( function ( key ) { return key !== _ _data _x ; } ) ;
var i = 0 ;
@ -350,43 +359,59 @@
// cache as original id keyed
targets . forEach ( function ( d ) {
_ addCache( d . id _org , d ) ;
addCache ( d . id _org , d ) ;
} ) ;
return targets ;
}
var _maxDataCount = function ( ) {
function maxDataCount ( ) {
return d3 . max ( c3 . data . targets , function ( t ) { return t . values . length ; } ) ;
}
var _targetsNum = function ( ) {
return Object . keys ( c3 . data . targets ) . length ;
}
function isLineType ( id ) {
return ! ( id in _ _data _types ) || _ _data _types [ id ] === 'line' ;
}
function isBarType ( id ) {
return _ _data _types [ id ] === 'bar' ;
}
function category ( i ) {
return i < _ _axis _x _categories . length ? _ _axis _x _categories [ i ] : i ;
}
var _getBrushRatio = function ( ) {
if ( brush . empty ( ) ) return 1 ;
var domain = x2 . domain ( ) , extent = brush . extent ( ) ;
return ( domain [ 1 ] - domain [ 0 ] ) / ( extent [ 1 ] - extent [ 0 ] ) ;
//-- Color --//
function generateColor ( _colors , _pattern ) {
var ids = [ ] ,
colors = _colors ,
pattern = ( _pattern !== null ) ? _pattern : [ '#1f77b4' , '#ff7f0e' , '#2ca02c' , '#d62728' , '#9467bd' , '#8c564b' , '#e377c2' , '#7f7f7f' , '#bcbd22' , '#17becf' ] ; //same as d3.scale.category10()
return function ( id ) {
// if specified, choose that color
if ( id in colors ) return _colors [ id ] ;
// if not specified, choose from pattern
if ( ! ( ids . indexOf ( id ) >= 0 ) ) {
ids . push ( id ) ;
}
return pattern [ ids . indexOf ( id ) % pattern . length ] ;
}
} ;
var _dist = function ( _this , _x , _y ) {
//-- Util --//
function dist ( _this , _x , _y ) {
var mouse = d3 . mouse ( _this ) ;
return Math . sqrt ( Math . pow ( x ( _x ) - mouse [ 0 ] , 2 ) + Math . pow ( y ( _y ) - mouse [ 1 ] , 2 ) )
}
function isWithinRegions ( x , regions ) {
for ( var i = 0 ; i < regions . length ; i ++ ) {
if ( regions [ i ] . start < x && x <= regions [ i ] . end ) return true ;
}
return false ;
}
//-- Selection --//
var _selectPoint = function ( target , d , i ) {
function selectPoint ( target , d , i ) {
_ _point _onselected ( target , d ) ;
// add selected-circle on low layer g
main . select ( ".selected-circles-" + d . id ) . selectAll ( '.selected-circle-' + i )
@ -400,108 +425,20 @@
. transition ( ) . duration ( 100 )
. attr ( "r" , _ _point _select _r ) ;
} ;
var _unselectPoint = function ( target , d , i ) {
function unselectPoint ( target , d , i ) {
_ _point _onunselected ( target , d ) ;
// remove selected-circle from low layer g
main . select ( ".selected-circles-" + d . id ) . selectAll ( ".selected-circle-" + i )
. transition ( ) . duration ( 100 ) . attr ( 'r' , 0 )
. remove ( ) ;
} ;
var _togglePoint = function ( selected , target , d , i ) {
( selected ) ? _ selectPoint( target , d , i ) : _ unselectPoint( target , d , i ) ;
function togglePoint ( selected , target , d , i ) {
( selected ) ? selectPoint ( target , d , i ) : unselectPoint ( target , d , i ) ;
} ;
// update - called when redraw
c3 . update = function ( withTransition ) {
x . domain ( brush . empty ( ) ? x2 . domain ( ) : brush . extent ( ) ) ;
//-- Shape --//
// ticks for x-axis
// ATTENTION: call here to update tickOffset
main . selectAll ( ".x.axis" ) . call ( xAxis ) ;
// grid
if ( _ _grid _x _show ) {
var xgridData = null ;
if ( _ _grid _x _type === 'year' ) {
xgridData = [ ] ;
firstYear = firstDate . getFullYear ( ) ;
lastYear = lastDate . getFullYear ( ) ;
for ( var year = firstYear ; year <= lastYear ; year ++ ) {
xgridData . push ( new Date ( year + '-01-01 00:00:00' ) ) ;
}
} else {
xgridData = x . ticks ( 10 ) ;
}
var xgrid = main . select ( 'g.xgrid' ) . selectAll ( "line.xgrid" )
. data ( xgridData ) ;
// Enter
xgrid . enter ( ) . append ( 'line' ) . attr ( "class" , "xgrid" ) ;
// Exit
xgrid . exit ( ) . remove ( ) ;
// Update
main . selectAll ( "line.xgrid" )
. attr ( "class" , "xgrid" )
. attr ( "x1" , x )
. attr ( "x2" , x )
. attr ( "y1" , margin . top )
. attr ( "y2" , height ) ;
}
if ( _ _grid _x _lines ) {
var xgridLine = main . selectAll ( "g.xgrid-line" ) ;
xgridLine . selectAll ( 'line' )
. attr ( "x1" , function ( d ) { return x ( d . value ) ; } )
. attr ( "x2" , function ( d ) { return x ( d . value ) ; } ) ;
xgridLine . selectAll ( 'text' )
. attr ( "x" , function ( d ) { return x ( d . value ) ; } ) ;
}
// line and cricle
var mainPath = main . selectAll ( '.target' ) . selectAll ( 'path' ) ;
if ( withTransition ) mainPath = mainPath . transition ( ) ;
mainPath . attr ( "d" , function ( d ) { return _lineWithRegions ( d . values , _ _data _regions [ d . id ] ) ; } ) ;
var mainCircle = main . selectAll ( '.target' ) . selectAll ( 'circle' ) ;
if ( withTransition ) mainCircle = mainCircle . transition ( ) ;
mainCircle . attr ( "cx" , function ( d ) { return x ( d . x ) ; } )
. attr ( "cy" , function ( d ) { return y ( d . value ) ; } ) ;
var targetsNum = Object . keys ( c3 . data . targets ) . length ,
barWidth = ( xAxis . tickOffset ( ) * 2 * 0.6 ) / targetsNum ;
var mainBar = main . selectAll ( '.target' ) . selectAll ( 'rect.target-bar' ) ;
if ( withTransition ) mainBar = mainBar . transition ( ) ;
mainBar . attr ( "width" , barWidth )
. attr ( "x" , function ( d ) { return x ( d . x ) - barWidth * ( targetsNum / 2 - d . i ) ; } ) ;
if ( _ _subchart _show ) {
var contextPath = context . selectAll ( '.target' ) . selectAll ( 'path' ) ;
if ( withTransition ) contextPath = contextPath . transition ( ) ;
contextPath . attr ( "d" , function ( d ) { return line2 ( d . values ) ; } ) ;
}
// circles for select
main . selectAll ( '.selected-circle' )
. attr ( "cx" , function ( d ) { return x ( d . x ) ; } )
. attr ( "cy" , function ( d ) { return y ( d . value ) ; } ) ;
// rect for mouseover
var w = ( ( width * _getBrushRatio ( ) ) / ( _maxDataCount ( ) - 1 ) ) ;
main . selectAll ( 'rect.event-rect' )
. attr ( "width" , w )
. attr ( "x" , function ( d ) { return x ( d . x ) - ( w / 2 ) ; } ) ;
main . selectAll ( 'rect.region' )
. attr ( "x" , regionStart )
. attr ( "width" , regionWidth ) ;
}
var _isWithinRegions = function ( d , regions ) {
for ( var i = 0 ; i < regions . length ; i ++ ) {
if ( regions [ i ] . start < d . x && d . x <= regions [ i ] . end ) return true ;
}
return false ;
}
var _lineWithRegions = function ( d , regions ) {
function lineWithRegions ( d , regions ) {
var prev = - 1 ,
s = "M" ;
@ -520,7 +457,7 @@
// Generate
for ( var i = 0 ; i < d . length ; i ++ ) {
// Draw as normal
if ( typeof regions === 'undefined' || ! _ isWithinRegions( d [ i ] , regions ) ) {
if ( typeof regions === 'undefined' || ! isWithinRegions ( d [ i ] . x , regions ) ) {
s += " " + x ( d [ i ] . x ) + " " + y ( d [ i ] . value ) ;
}
// Draw with region
@ -541,12 +478,9 @@
return s ;
} ;
/*-- Bind Events --*/
/*-- Define brush --*/
// Brush
var brush = d3 . svg . brush ( )
. x ( x2 )
. on ( "brush" , c3 . update ) ;
var brush = d3 . svg . brush ( ) . x ( x2 ) . on ( "brush" , update ) ;
/*-- Draw Chart --*/
@ -554,17 +488,17 @@
var firstDate = null ,
lastDate = null ;
var _init = function ( data ) {
var targets = c3 . data . targets = _ convertDataToTargets( data ) ;
function init ( data ) {
var targets = c3 . data . targets = convertDataToTargets ( data ) ;
// TODO: set names if names not specified
x . domain ( d3 . extent ( data . map ( function ( d ) { return d . x ; } ) ) ) ;
y . domain ( _ getYDomain( targets ) ) ;
y . domain ( getYDomain ( targets ) ) ;
x2 . domain ( x . domain ( ) ) ;
y2 . domain ( y . domain ( ) ) ;
/*-- Focus Region --*/
/*-- Main Region --*/
var grid = main . append ( 'g' )
. attr ( "clip-path" , clipPath )
@ -654,7 +588,7 @@
/*-- Cover whole with rects for events --*/
var w = ( ( width * _getBrush Ratio( ) ) / ( _ maxDataCount( ) - 1 ) ) ;
var w = ( ( width * getXDomain Ratio( ) ) / ( maxDataCount ( ) - 1 ) ) ;
main . select ( '.chart' ) . append ( "g" )
. attr ( "class" , "event-rects" )
@ -734,7 +668,7 @@
d3 . select ( '.event-rect-' + i )
. style ( 'cursor' , null ) ;
} )
. filter ( function ( d ) { return _ dist( this , d . x , d . value ) < _ _point _select _r ; } )
. filter ( function ( d ) { return dist ( this , d . x , d . value ) < _ _point _select _r ; } )
. each ( function ( d ) {
var _this = d3 . select ( this ) ;
if ( ! _this . classed ( '_e_' ) ) {
@ -747,10 +681,10 @@
main . selectAll ( '.target-circle-' + i ) . each ( function ( d , x ) {
var _this = d3 . select ( this ) ,
_selected = _this . classed ( '_s_' ) ;
if ( _ _data _selection _grouped || _ dist( this , d . x , d . value ) < _ _point _select _r * 1.5 ) {
if ( _ _data _selection _grouped || dist ( this , d . x , d . value ) < _ _point _select _r * 1.5 ) {
if ( _ _data _selection _enabled && _ _data _selection _isselectable ( d ) ) {
_this . classed ( '_s_' , ! _selected ) ;
_ togglePoint( ! _selected , _this , d , i ) ;
togglePoint ( ! _selected , _this , d , i ) ;
}
_ _point _onclick ( d , _this ) ;
}
@ -785,7 +719,7 @@
_this . classed ( '_i_' , ! _included ) ;
// TODO: included/unincluded callback here
_this . classed ( '_s_' , ! _selected ) ;
_ togglePoint( ! _selected , _this , d , i ) ;
togglePoint ( ! _selected , _this , d , i ) ;
}
} ) ;
} )
@ -839,7 +773,7 @@
// ATTENTION: This must be called AFTER chart rendered and BEFORE brush called.
// Update extetn for Brush
if ( _ _subchart _default !== null ) {
brush . extent ( ( isTimeSeries ) ? _ _subchart _default ( firstDate , lastDate ) : _ _subchart _default ( 0 , _ maxDataCount( ) - 1 ) ) ;
brush . extent ( ( isTimeSeries ) ? _ _subchart _default ( firstDate , lastDate ) : _ _subchart _default ( 0 , maxDataCount ( ) - 1 ) ) ;
}
// Add extent rect for Brush
@ -859,91 +793,98 @@
/*-- Legend Region --*/
if ( _ _legend _show ) {
_draw _legend ( targets ) ;
}
if ( _ _legend _show ) drawLegend ( targets ) ;
// Update main chart with settings
c3 . update ( ) ;
/*-- Draw chart for each data --*/
_draw ( targets ) ;
update ( ) ;
// Draw chart for each data
draw ( targets ) ;
} ;
var _draw _legend = function ( targets ) {
var ids = targets . map ( function ( d ) { return d . id ; } ) ;
// Define g for legend area
var l = legend . selectAll ( '.legend-item' )
. data ( ids )
. enter ( ) . append ( 'g' )
. attr ( 'class' , function ( d ) { return 'legend-item legend-item-' + d ; } )
. style ( 'cursor' , 'pointer' )
. on ( 'click' , function ( d ) {
_ _legend _item _onclick ( d ) ;
} )
. on ( 'mouseover' , function ( d ) {
d3 . selectAll ( '.legend-item' ) . filter ( function ( _d ) { return _d !== d ; } )
. transition ( ) . duration ( 100 )
. style ( 'opacity' , 0.3 ) ;
c3 . defocus ( ) ;
c3 . focus ( d ) ;
} )
. on ( 'mouseout' , function ( d ) {
d3 . selectAll ( '.legend-item' )
. transition ( ) . duration ( 100 )
. style ( 'opacity' , 1 ) ;
c3 . revert ( ) ;
} ) ;
function update ( withTransition ) {
x . domain ( brush . empty ( ) ? x2 . domain ( ) : brush . extent ( ) ) ;
l . append ( 'rect' ) . classed ( "legend-item-event" , true ) . attr ( 'x' , - 200 ) ;
l . append ( 'rect' ) . classed ( "legend-item-tile" , true ) . attr ( 'x' , - 200 ) ;
l . append ( 'text' ) . attr ( 'x' , - 200 ) ;
// ticks for x-axis
// ATTENTION: call here to update tickOffset
main . selectAll ( ".x.axis" ) . call ( xAxis ) ;
legend . selectAll ( 'rect.legend-item-event' )
. data ( ids )
. style ( 'fill-opacity' , 0 )
. attr ( 'width' , _ _legend _item _width )
. attr ( 'height' , 24 )
. attr ( 'y' , function ( d , i ) { return legendHeight / 2 - 16 ; } ) ;
// grid
if ( _ _grid _x _show ) {
var xgridData = null ;
if ( _ _grid _x _type === 'year' ) {
xgridData = [ ] ;
firstYear = firstDate . getFullYear ( ) ;
lastYear = lastDate . getFullYear ( ) ;
for ( var year = firstYear ; year <= lastYear ; year ++ ) {
xgridData . push ( new Date ( year + '-01-01 00:00:00' ) ) ;
}
} else {
xgridData = x . ticks ( 10 ) ;
}
legend . selectAll ( 'rect.legend-item-tile' )
. data ( ids )
. style ( 'fill' , function ( d ) { return color ( d ) ; } )
. attr ( 'width' , 10 )
. attr ( 'height' , 10 )
. attr ( 'y' , function ( d , i ) { return legendHeight / 2 - 9 ; } ) ;
var xgrid = main . select ( 'g.xgrid' ) . selectAll ( "line.xgrid" )
. data ( xgridData ) ;
// Enter
xgrid . enter ( ) . append ( 'line' ) . attr ( "class" , "xgrid" ) ;
// Exit
xgrid . exit ( ) . remove ( ) ;
// Update
main . selectAll ( "line.xgrid" )
. attr ( "class" , "xgrid" )
. attr ( "x1" , x )
. attr ( "x2" , x )
. attr ( "y1" , margin . top )
. attr ( "y2" , height ) ;
}
if ( _ _grid _x _lines ) {
var xgridLine = main . selectAll ( "g.xgrid-line" ) ;
xgridLine . selectAll ( 'line' )
. attr ( "x1" , function ( d ) { return x ( d . value ) ; } )
. attr ( "x2" , function ( d ) { return x ( d . value ) ; } ) ;
xgridLine . selectAll ( 'text' )
. attr ( "x" , function ( d ) { return x ( d . value ) ; } ) ;
}
legend . selectAll ( 'text' )
. data ( ids )
. text ( function ( d ) { return _ _data _names [ d ] ; } )
. attr ( 'y' , function ( d , i ) { return legendHeight / 2 ; } ) ;
// line and cricle
var mainPath = main . selectAll ( '.target' ) . selectAll ( 'path' ) ;
if ( withTransition ) mainPath = mainPath . transition ( ) ;
mainPath . attr ( "d" , function ( d ) { return lineWithRegions ( d . values , _ _data _regions [ d . id ] ) ; } ) ;
var mainCircle = main . selectAll ( '.target' ) . selectAll ( 'circle' ) ;
if ( withTransition ) mainCircle = mainCircle . transition ( ) ;
mainCircle . attr ( "cx" , function ( d ) { return x ( d . x ) ; } )
. attr ( "cy" , function ( d ) { return y ( d . value ) ; } ) ;
_update _legend ( targets ) ;
} ;
var _update _legend = function ( targets ) {
var ids = targets . map ( function ( d ) { return d . id ; } ) ,
padding = width / 2 - _ _legend _item _width * Object . keys ( targets ) . length / 2 ;
var targetsNum = Object . keys ( c3 . data . targets ) . length ,
barWidth = ( xAxis . tickOffset ( ) * 2 * 0.6 ) / targetsNum ;
var mainBar = main . selectAll ( '.target' ) . selectAll ( 'rect.target-bar' ) ;
if ( withTransition ) mainBar = mainBar . transition ( ) ;
mainBar . attr ( "width" , barWidth )
. attr ( "x" , function ( d ) { return x ( d . x ) - barWidth * ( targetsNum / 2 - d . i ) ; } ) ;
legend . selectAll ( 'rect.legend-item-event' )
. data ( ids )
. transition ( )
. attr ( 'x' , function ( d , i ) { return padding + _ _legend _item _width * i ; } )
if ( _ _subchart _show ) {
var contextPath = context . selectAll ( '.target' ) . selectAll ( 'path' ) ;
if ( withTransition ) contextPath = contextPath . transition ( ) ;
contextPath . attr ( "d" , function ( d ) { return line2 ( d . values ) ; } ) ;
}
legend . selectAll ( 'rect.legend-item-tile' )
. data ( ids )
. transition ( )
. attr ( 'x' , function ( d , i ) { return padding + _ _legend _item _width * i ; } )
// circles for select
main . selectAll ( '.selected-circle' )
. attr ( "cx" , function ( d ) { return x ( d . x ) ; } )
. attr ( "cy" , function ( d ) { return y ( d . value ) ; } ) ;
legend . selectAll ( 'text' )
. data ( ids )
. transition ( )
. attr ( 'x' , function ( d , i ) { return padding + _ _legend _item _width * i + 14 ; } )
} ;
// rect for mouseover
var w = ( ( width * getXDomainRatio ( ) ) / ( maxDataCount ( ) - 1 ) ) ;
console . log ( w ) ;
main . selectAll ( 'rect.event-rect' )
. attr ( "width" , w )
. attr ( "x" , function ( d ) { return x ( d . x ) - ( w / 2 ) ; } ) ;
main . selectAll ( 'rect.region' )
. attr ( "x" , regionStart )
. attr ( "width" , regionWidth ) ;
}
var _draw = function ( targets ) {
function draw ( targets ) {
/*-- Main --*/
@ -958,7 +899,7 @@
// Lines for each data
f . append ( "path" )
. attr ( "class" , function ( d ) { return "target-line target-line-" + d . id ; } )
. attr ( "d" , function ( d ) { return _ lineWithRegions( d . values , _ _data _regions [ d . id ] ) ; } )
. attr ( "d" , function ( d ) { return lineWithRegions ( d . values , _ _data _regions [ d . id ] ) ; } )
. style ( "stroke" , function ( d ) { return color ( d . id ) ; } )
. style ( "opacity" , function ( d ) { return isLineType ( d . id ) ? 1 : 0 ; } ) ;
@ -981,7 +922,7 @@
_selected = _this . classed ( '_s_' ) ;
if ( _ _data _selection _enabled && _ _data _selection _isselectable ( d ) ) {
_this . classed ( '_s_' , ! _selected ) ;
_ togglePoint( ! _selected , _this , d , i ) ;
togglePoint ( ! _selected , _this , d , i ) ;
}
_ _point _onclick ( d , _this ) ;
} )
@ -989,7 +930,7 @@
// Rects for each data
var targetsNum = _targetsNum ( ) ,
var targetsNum = Object . keys ( c3 . data . targets ) . length ,
barWidth = ( xAxis . tickOffset ( ) * 2 * 0.6 ) / targetsNum ;
f . append ( 'g' )
@ -1009,7 +950,7 @@
main . selectAll ( '.target-line' )
. data ( targets )
. transition ( )
. attr ( "d" , function ( d ) { return _ lineWithRegions( d . values , _ _data _regions [ d . id ] ) ; } ) ;
. attr ( "d" , function ( d ) { return lineWithRegions ( d . values , _ _data _regions [ d . id ] ) ; } ) ;
main . selectAll ( '.target-circles' )
. data ( targets )
@ -1063,7 +1004,7 @@
/*-- Legend --*/
if ( _ _legend _show ) {
_draw _l egend( targets ) ;
drawL egend( targets ) ;
}
/*-- Show --*/
@ -1074,7 +1015,7 @@
. style ( "opacity" , 1 ) ;
} ;
var _load = function ( targets , done ) {
function load ( targets , done ) {
// Update/Add data
c3 . data . targets . forEach ( function ( d ) {
for ( var i = 0 ; i < targets . length ; i ++ ) {
@ -1088,16 +1029,90 @@
c3 . data . targets = c3 . data . targets . concat ( targets ) ; // add remained
if ( _ _axis _y _rescale ) {
y . domain ( _ getYDomain( c3 . data . targets ) ) ;
y . domain ( getYDomain ( c3 . data . targets ) ) ;
y2 . domain ( y . domain ( ) ) ;
main . select ( '.y.axis' ) . transition ( ) . call ( yAxis ) ;
}
_ draw( c3 . data . targets ) ;
draw ( c3 . data . targets ) ;
done ( ) ;
} ;
/*-- Draw Legend --*/
function drawLegend ( targets ) {
var ids = targets . map ( function ( d ) { return d . id ; } ) ;
// Define g for legend area
var l = legend . selectAll ( '.legend-item' )
. data ( ids )
. enter ( ) . append ( 'g' )
. attr ( 'class' , function ( d ) { return 'legend-item legend-item-' + d ; } )
. style ( 'cursor' , 'pointer' )
. on ( 'click' , function ( d ) {
_ _legend _item _onclick ( d ) ;
} )
. on ( 'mouseover' , function ( d ) {
d3 . selectAll ( '.legend-item' ) . filter ( function ( _d ) { return _d !== d ; } )
. transition ( ) . duration ( 100 )
. style ( 'opacity' , 0.3 ) ;
c3 . defocus ( ) ;
c3 . focus ( d ) ;
} )
. on ( 'mouseout' , function ( d ) {
d3 . selectAll ( '.legend-item' )
. transition ( ) . duration ( 100 )
. style ( 'opacity' , 1 ) ;
c3 . revert ( ) ;
} ) ;
l . append ( 'rect' ) . classed ( "legend-item-event" , true ) . attr ( 'x' , - 200 ) ;
l . append ( 'rect' ) . classed ( "legend-item-tile" , true ) . attr ( 'x' , - 200 ) ;
l . append ( 'text' ) . attr ( 'x' , - 200 ) ;
legend . selectAll ( 'rect.legend-item-event' )
. data ( ids )
. style ( 'fill-opacity' , 0 )
. attr ( 'width' , _ _legend _item _width )
. attr ( 'height' , 24 )
. attr ( 'y' , function ( d , i ) { return legendHeight / 2 - 16 ; } ) ;
legend . selectAll ( 'rect.legend-item-tile' )
. data ( ids )
. style ( 'fill' , function ( d ) { return color ( d ) ; } )
. attr ( 'width' , 10 )
. attr ( 'height' , 10 )
. attr ( 'y' , function ( d , i ) { return legendHeight / 2 - 9 ; } ) ;
legend . selectAll ( 'text' )
. data ( ids )
. text ( function ( d ) { return _ _data _names [ d ] ; } )
. attr ( 'y' , function ( d , i ) { return legendHeight / 2 ; } ) ;
updateLegend ( targets ) ;
} ;
function updateLegend ( targets ) {
var ids = targets . map ( function ( d ) { return d . id ; } ) ,
padding = width / 2 - _ _legend _item _width * Object . keys ( targets ) . length / 2 ;
legend . selectAll ( 'rect.legend-item-event' )
. data ( ids )
. transition ( )
. attr ( 'x' , function ( d , i ) { return padding + _ _legend _item _width * i ; } )
legend . selectAll ( 'rect.legend-item-tile' )
. data ( ids )
. transition ( )
. attr ( 'x' , function ( d , i ) { return padding + _ _legend _item _width * i ; } )
legend . selectAll ( 'text' )
. data ( ids )
. transition ( )
. attr ( 'x' , function ( d , i ) { return padding + _ _legend _item _width * i + 14 ; } )
} ;
/*-- Event Handling --*/
function getTargetSelector ( target ) {
@ -1143,24 +1158,24 @@
args . done = function ( ) { } ;
}
// use cache if exists
if ( 'cacheIds' in args && _ hasCaches( args . cacheIds ) ) {
_ load( _ getCaches( args . cacheIds ) , args . done ) ;
if ( 'cacheIds' in args && hasCaches ( args . cacheIds ) ) {
load ( getCaches ( args . cacheIds ) , args . done ) ;
return ;
}
// load data
if ( 'data' in args ) {
_ load( _ convertDataToTargets( data ) , args . done ) ;
load ( convertDataToTargets ( data ) , args . done ) ;
}
else if ( 'url' in args ) {
d3 . csv ( args . url , function ( error , data ) {
_ load( _ convertDataToTargets( data ) , args . done ) ;
load ( convertDataToTargets ( data ) , args . done ) ;
} ) ;
}
else if ( 'rows' in args ) {
_ load( _ convertDataToTargets( _ convertRowsToData( args . rows ) ) , args . done ) ;
load ( convertDataToTargets ( convertRowsToData ( args . rows ) ) , args . done ) ;
}
else if ( 'columns' in args ) {
_ load( _ convertDataToTargets( _ convertColumnsToData( args . columns ) ) , args . done ) ;
load ( convertDataToTargets ( convertColumnsToData ( args . columns ) ) , args . done ) ;
}
else {
throw Error ( 'url or rows or columns is required.' ) ;
@ -1178,16 +1193,16 @@
if ( _ _legend _show ) {
d3 . selectAll ( '.legend-item-' + target ) . remove ( ) ;
_update _l egend( c3 . data . targets ) ;
updateL egend( c3 . data . targets ) ;
}
if ( _ _axis _y _rescale ) {
y . domain ( _ getYDomain( c3 . data . targets ) ) ;
y . domain ( getYDomain ( c3 . data . targets ) ) ;
y2 . domain ( y . domain ( ) ) ;
main . select ( '.y.axis' ) . transition ( ) . call ( yAxis ) ;
}
c3 . update ( true ) ;
update ( true ) ;
} ;
c3 . selected = function ( target ) {
@ -1205,10 +1220,10 @@
main . selectAll ( '.target-circles' ) . selectAll ( '.target-circle' ) . each ( function ( d , i ) {
if ( indices . indexOf ( i ) >= 0 ) {
if ( _ _data _selection _grouped || _ _data _selection _isselectable ( d ) ) {
_ selectPoint( d3 . select ( this ) . classed ( '_s_' , true ) , d , i ) ;
selectPoint ( d3 . select ( this ) . classed ( '_s_' , true ) , d , i ) ;
}
} else if ( typeof resetOther !== 'undefined' && resetOther ) {
_ unselectPoint( d3 . select ( this ) . classed ( '_s_' , false ) , d , i ) ;
unselectPoint ( d3 . select ( this ) . classed ( '_s_' , false ) , d , i ) ;
}
} ) ;
}
@ -1218,22 +1233,22 @@
main . selectAll ( '.target-circles' ) . selectAll ( '.target-circle' ) . each ( function ( d , i ) {
if ( typeof indices === 'undefined' || indices . indexOf ( i ) >= 0 ) {
if ( _ _data _selection _grouped || _ _data _selection _isselectable ( d ) ) {
_ unselectPoint( d3 . select ( this ) . classed ( '_s_' , false ) , d , i ) ;
unselectPoint ( d3 . select ( this ) . classed ( '_s_' , false ) , d , i ) ;
}
}
} ) ;
}
/*-- Load data and init chart --*/
/*-- Load data and init chart with defined functions --*/
if ( 'url' in config . data ) {
d3 . csv ( config . data . url , function ( error , data ) { _ init( data ) ; } ) ;
d3 . csv ( config . data . url , function ( error , data ) { init ( data ) ; } ) ;
}
else if ( 'rows' in config . data ) {
_ init( _ convertRowsToData( config . data . rows ) ) ;
init ( convertRowsToData ( config . data . rows ) ) ;
}
else if ( 'columns' in config . data ) {
_ init( _ convertColumnsToData( config . data . columns ) ) ;
init ( convertColumnsToData ( config . data . columns ) ) ;
}
else {
throw Error ( 'url or rows or columns is required.' ) ;
@ -1242,24 +1257,7 @@
return c3 ;
} ;
var _generateColor = function ( _colors , _pattern ) {
var ids = [ ] ,
colors = _colors ,
pattern = ( _pattern !== null ) ? _pattern : [ '#1f77b4' , '#ff7f0e' , '#2ca02c' , '#d62728' , '#9467bd' , '#8c564b' , '#e377c2' , '#7f7f7f' , '#bcbd22' , '#17becf' ] ; // same as d3.scale.category10()
return function ( id ) {
// if specified, choose that color
if ( id in colors ) return _colors [ id ] ;
// if not specified, choose from pattern
if ( ! ( ids . indexOf ( id ) >= 0 ) ) {
ids . push ( id ) ;
}
return pattern [ ids . indexOf ( id ) % pattern . length ] ;
}
} ;
var categoryAxis = function ( ) {
function categoryAxis ( ) {
var scale = d3 . scale . linear ( ) , orient = "bottom" , tickMajorSize = 6 , tickMinorSize = 6 , tickEndSize = 6 , tickPadding = 3 , tickCentered = false , tickTextNum = 30 , tickOffset = 0 , categories = [ ] ;
function axisX ( selection , x ) {
selection . attr ( "transform" , function ( d ) {