@ -51,6 +51,7 @@
backgroundOpacity : 0.85 // set to 0 to avoid background
} ,
xaxis : {
show : null , // null = auto-detect, true = always, false = never
position : "bottom" , // or "top"
mode : null , // null or "time"
color : null , // base color, labels, ticks
@ -64,6 +65,7 @@
tickFormatter : null , // fn: number -> string
labelWidth : null , // size of tick labels in pixels
labelHeight : null ,
reserveSpace : null , // whether to reserve space even if axis isn't shown
tickLength : null , // size in pixels of ticks, or "full" for whole line
alignTicksWithAxis : null , // axis number or null for no sync
@ -256,6 +258,7 @@
options . xaxes [ i ] = $ . extend ( true , { } , options . xaxis , options . xaxes [ i ] ) ;
for ( i = 0 ; i < Math . max ( 1 , options . yaxes . length ) ; ++ i )
options . yaxes [ i ] = $ . extend ( true , { } , options . yaxis , options . yaxes [ i ] ) ;
// backwards compatibility, to be removed in future
if ( options . xaxis . noTicks && options . xaxis . ticks == null )
options . xaxis . ticks = options . xaxis . noTicks ;
@ -282,6 +285,7 @@
if ( options . shadowSize != null )
options . series . shadowSize = options . shadowSize ;
// save options on axes for future reference
for ( i = 0 ; i < options . xaxes . length ; ++ i )
getOrCreateAxis ( xaxes , i + 1 ) . options = options . xaxes [ i ] ;
for ( i = 0 ; i < options . yaxes . length ; ++ i )
@ -331,6 +335,11 @@
return a ;
}
function allAxes ( ) {
// return flat array without annoying null entries
return $ . grep ( xaxes . concat ( yaxes ) , function ( a ) { return a ; } ) ;
}
function canvasToAxisCoords ( pos ) {
// return an object with x/y corresponding to all used axes
var res = { } , i , axis ;
@ -502,15 +511,6 @@
i , j , k , m , length ,
s , points , ps , x , y , axis , val , f , p ;
function initAxis ( axis , number ) {
if ( ! axis )
return ;
axis . datamin = topSentry ;
axis . datamax = bottomSentry ;
axis . used = false ;
}
function updateAxis ( axis , min , max ) {
if ( min < axis . datamin && min != - fakeInfinity )
axis . datamin = min ;
@ -518,10 +518,12 @@
axis . datamax = max ;
}
for ( i = 0 ; i < xaxes . length ; ++ i )
initAxis ( xaxes [ i ] ) ;
for ( i = 0 ; i < yaxes . length ; ++ i )
initAxis ( yaxes [ i ] ) ;
$ . each ( allAxes ( ) , function ( _ , axis ) {
// init axis
axis . datamin = topSentry ;
axis . datamax = bottomSentry ;
axis . used = false ;
} ) ;
for ( i = 0 ; i < series . length ; ++ i ) {
s = series [ i ] ;
@ -691,7 +693,7 @@
updateAxis ( s . yaxis , ymin , ymax ) ;
}
$ . each ( getUsedAxes( ) , function ( i , axis ) {
$ . each ( allAxes( ) , function ( _ , axis ) {
if ( axis . datamin == topSentry )
axis . datamin = null ;
if ( axis . datamax == bottomSentry )
@ -802,9 +804,6 @@
}
function measureTickLabels ( axis ) {
if ( ! axis )
return ;
var opts = axis . options , i , ticks = axis . ticks || [ ] , labels = [ ] ,
l , w = opts . labelWidth , h = opts . labelHeight , dummyDiv ;
@ -869,10 +868,7 @@
axis . labelHeight = h ;
}
function computeAxisBox ( axis ) {
if ( ! axis || ! axis . labelWidth || ! axis . labelHeight )
return ;
function computeAxisBoxFirstPhase ( axis ) {
// find the bounding box of the axis by looking at label
// widths/heights and ticks, make room by diminishing the
// plotOffset
@ -888,7 +884,7 @@
// determine axis margin
var samePosition = $ . grep ( all , function ( a ) {
return a && a . options . position == pos && ( a . labelHeight || a . labelWidth ) ;
return a && a . options . position == pos && a . reserveSpace ;
} ) ;
if ( $ . inArray ( axis , samePosition ) == samePosition . length - 1 )
axismargin = 0 ; // outermost
@ -898,7 +894,7 @@
tickLength = "full" ;
var sameDirection = $ . grep ( all , function ( a ) {
return a && ( a . labelHeight || a . labelWidth ) ;
return a && a . reserveSpace ;
} ) ;
var innermost = $ . inArray ( axis , sameDirection ) == 0 ;
@ -941,10 +937,7 @@
axis . innermost = innermost ;
}
function fixupAxisBox ( axis ) {
if ( ! axis || ! axis . labelWidth || ! axis . labelHeight )
return ;
function computeAxisBoxSecondPhase ( axis ) {
// set remaining bounding box coordinates
if ( axis . direction == "x" ) {
axis . box . left = plotOffset . left ;
@ -957,40 +950,43 @@
}
function setupGrid ( ) {
var axes = getUsedAxes ( ) , j , k ;
var i, axes = allAxes ( ) ;
// compute axis intervals
for ( k = 0 ; k < axes . length ; ++ k )
setRange ( axes [ k ] ) ;
// first calculate the plot and axis box dimensions
$ . each ( axes , function ( _ , axis ) {
axis . show = axis . options . show ;
if ( axis . show == null )
axis . show = axis . used ; // by default an axis is visible if it's got data
axis . reserveSpace = axis . show || axis . options . reserveSpace ;
setRange ( axis ) ;
} ) ;
allocatedAxes = $ . grep ( axes , function ( axis ) { return axis . reserveSpace ; } ) ;
plotOffset . left = plotOffset . right = plotOffset . top = plotOffset . bottom = 0 ;
if ( options . grid . show ) {
// make the ticks
for ( k = 0 ; k < axes . length ; ++ k ) {
setupTickGeneration ( axes [ k ] ) ;
setTicks ( axes [ k ] ) ;
snapRangeToTicks ( axes [ k ] , axes [ k ] . ticks ) ;
}
$ . each ( allocatedAxes , function ( _ , axis ) {
// make the ticks
setupTickGeneration ( axis ) ;
setTicks ( axis ) ;
snapRangeToTicks ( axis , axis . ticks ) ;
// find labelWidth/Height for axis
measureTickLabels ( axis ) ;
} ) ;
// find labelWidth/Height, do this on all, not just
// used as we might need to reserve space for unused
// too if their labelWidth/Height is set
for ( j = 0 ; j < xaxes . length ; ++ j )
measureTickLabels ( xaxes [ j ] ) ;
for ( j = 0 ; j < yaxes . length ; ++ j )
measureTickLabels ( yaxes [ j ] ) ;
// compute the axis boxes, start from the outside (reverse order)
for ( j = xaxes . length - 1 ; j >= 0 ; -- j )
computeAxisBox ( xaxes [ j ] ) ;
for ( j = yaxes . length - 1 ; j >= 0 ; -- j )
computeAxisBox ( yaxes [ j ] ) ;
// with all dimensions in house, we can compute the
// axis boxes, start from the outside (reverse order)
for ( i = allocatedAxes . length - 1 ; i >= 0 ; -- i )
computeAxisBoxFirstPhase ( allocatedAxes [ i ] ) ;
// make sure we've got enough space for things that
// might stick out
var maxOutset = 0 ;
for ( var i = 0 ; i < series . length ; ++ i )
for ( i = 0 ; i < series . length ; ++ i )
maxOutset = Math . max ( maxOutset , 2 * ( series [ i ] . points . radius + series [ i ] . points . lineWidth / 2 ) ) ;
for ( var a in plotOffset ) {
@ -1003,13 +999,15 @@
plotHeight = canvasHeight - plotOffset . bottom - plotOffset . top ;
// now we got the proper plotWidth/Height, we can compute the scaling
for ( k = 0 ; k < axes . length ; ++ k )
setTransformationHelpers ( axes [ k ] ) ;
$ . each ( axes , function ( _ , axis ) {
setTransformationHelpers ( axis ) ;
} ) ;
if ( options . grid . show ) {
for ( k = 0 ; k < axes . length ; ++ k )
fixupAxisBox ( axes [ k ] ) ;
$ . each ( allocatedAxes , function ( _ , axis ) {
computeAxisBoxSecondPhase ( axis ) ;
} ) ;
insertAxisLabels ( ) ;
}
@ -1028,7 +1026,7 @@
if ( opts . min == null )
min -= widen ;
// alway widen max if we couldn't widen min to ensure we
// alway s widen max if we couldn't widen min to ensure we
// don't fall into min == max which doesn't work
if ( opts . max == null || opts . min != null )
max += widen ;
@ -1062,12 +1060,10 @@
var noTicks ;
if ( typeof opts . ticks == "number" && opts . ticks > 0 )
noTicks = opts . ticks ;
else if ( axis . direction == "x" )
// heuristic based on the model a*sqrt(x) fitted to
// some reasonable data points
noTicks = 0.3 * Math . sqrt ( canvasWidth ) ;
else
noTicks = 0.3 * Math . sqrt ( canvasHeight ) ;
// heuristic based on the model a*sqrt(x) fitted to
// some data points that seemed reasonable
noTicks = 0.3 * Math . sqrt ( axis . direction == "x" ? canvasWidth : canvasHeight ) ;
var delta = ( axis . max - axis . min ) / noTicks ,
size , generator , unit , formatter , i , magn , norm ;
@ -1330,8 +1326,6 @@
}
function setTicks ( axis ) {
axis . ticks = [ ] ;
var oticks = axis . options . ticks , ticks = [ ] ;
if ( oticks == null || ( typeof oticks == "number" && oticks > 0 ) )
ticks = axis . tickGenerator ( axis ) ;
@ -1345,19 +1339,21 @@
// clean up/labelify the supplied ticks, copy them over
var i , v ;
axis . ticks = [ ] ;
for ( i = 0 ; i < ticks . length ; ++ i ) {
var label = null ;
var t = ticks [ i ] ;
if ( typeof t == "object" ) {
v = t [ 0 ] ;
v = + t [ 0 ] ;
if ( t . length > 1 )
label = t [ 1 ] ;
}
else
v = t ;
v = + t ;
if ( label == null )
label = axis . tickFormatter ( v , axis ) ;
axis . ticks [ i ] = { v : v , label : label } ;
if ( ! isNaN ( v ) )
axis . ticks . push ( { v : v , label : label } ) ;
}
}
@ -1513,14 +1509,13 @@
}
// draw the ticks
var axes = getUsed Axes( ) , bw = options . grid . borderWidth ;
var axes = all Axes( ) , bw = options . grid . borderWidth ;
for ( var j = 0 ; j < axes . length ; ++ j ) {
var axis = axes [ j ] , box = axis . box ,
t = axis . tickLength , x , y , xoff , yoff ;
if ( axis . ticks . length == 0 )
continue ;
if ( ! axis . show || axis . ticks . length == 0 )
continue
ctx . strokeStyle = axis . options . tickColor || $ . color . parse ( axis . options . color ) . scale ( 'a' , 0.22 ) . toString ( ) ;
ctx . lineWidth = 1 ;
@ -1618,9 +1613,11 @@
var html = [ '<div class="tickLabels" style="font-size:smaller">' ] ;
var axes = getUsed Axes( ) ;
var axes = all Axes( ) ;
for ( var j = 0 ; j < axes . length ; ++ j ) {
var axis = axes [ j ] , box = axis . box ;
if ( ! axis . show )
continue ;
//debug: html.push('<div style="position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')
html . push ( '<div class="' + axis . direction + 'Axis ' + axis . direction + axis . n + 'Axis" style="color:' + axis . options . color + '">' ) ;
for ( var i = 0 ; i < axis . ticks . length ; ++ i ) {