2016-05-24 16:09:28 -07:00
/ * !
* Chart . js
* http : //chartjs.org/
* Version : 2.1 . 3
*
* Copyright 2016 Nick Downie
* Released under the MIT license
* https : //github.com/chartjs/Chart.js/blob/master/LICENSE.md
* /
( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
/* MIT license */
var colorNames = require ( 'color-name' ) ;
module . exports = {
getRgba : getRgba ,
getHsla : getHsla ,
getRgb : getRgb ,
getHsl : getHsl ,
getHwb : getHwb ,
getAlpha : getAlpha ,
hexString : hexString ,
rgbString : rgbString ,
rgbaString : rgbaString ,
percentString : percentString ,
percentaString : percentaString ,
hslString : hslString ,
hslaString : hslaString ,
hwbString : hwbString ,
keyword : keyword
}
function getRgba ( string ) {
if ( ! string ) {
return ;
}
var abbr = /^#([a-fA-F0-9]{3})$/ ,
hex = /^#([a-fA-F0-9]{6})$/ ,
rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/ ,
per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/ ,
keyword = /(\w+)/ ;
var rgb = [ 0 , 0 , 0 ] ,
a = 1 ,
match = string . match ( abbr ) ;
if ( match ) {
match = match [ 1 ] ;
for ( var i = 0 ; i < rgb . length ; i ++ ) {
rgb [ i ] = parseInt ( match [ i ] + match [ i ] , 16 ) ;
}
}
else if ( match = string . match ( hex ) ) {
match = match [ 1 ] ;
for ( var i = 0 ; i < rgb . length ; i ++ ) {
rgb [ i ] = parseInt ( match . slice ( i * 2 , i * 2 + 2 ) , 16 ) ;
}
}
else if ( match = string . match ( rgba ) ) {
for ( var i = 0 ; i < rgb . length ; i ++ ) {
rgb [ i ] = parseInt ( match [ i + 1 ] ) ;
}
a = parseFloat ( match [ 4 ] ) ;
}
else if ( match = string . match ( per ) ) {
for ( var i = 0 ; i < rgb . length ; i ++ ) {
rgb [ i ] = Math . round ( parseFloat ( match [ i + 1 ] ) * 2.55 ) ;
}
a = parseFloat ( match [ 4 ] ) ;
}
else if ( match = string . match ( keyword ) ) {
if ( match [ 1 ] == "transparent" ) {
return [ 0 , 0 , 0 , 0 ] ;
}
rgb = colorNames [ match [ 1 ] ] ;
if ( ! rgb ) {
return ;
}
}
for ( var i = 0 ; i < rgb . length ; i ++ ) {
rgb [ i ] = scale ( rgb [ i ] , 0 , 255 ) ;
}
if ( ! a && a != 0 ) {
a = 1 ;
}
else {
a = scale ( a , 0 , 1 ) ;
}
rgb [ 3 ] = a ;
return rgb ;
}
function getHsla ( string ) {
if ( ! string ) {
return ;
}
var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/ ;
var match = string . match ( hsl ) ;
if ( match ) {
var alpha = parseFloat ( match [ 4 ] ) ;
var h = scale ( parseInt ( match [ 1 ] ) , 0 , 360 ) ,
s = scale ( parseFloat ( match [ 2 ] ) , 0 , 100 ) ,
l = scale ( parseFloat ( match [ 3 ] ) , 0 , 100 ) ,
a = scale ( isNaN ( alpha ) ? 1 : alpha , 0 , 1 ) ;
return [ h , s , l , a ] ;
}
}
function getHwb ( string ) {
if ( ! string ) {
return ;
}
var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/ ;
var match = string . match ( hwb ) ;
if ( match ) {
var alpha = parseFloat ( match [ 4 ] ) ;
var h = scale ( parseInt ( match [ 1 ] ) , 0 , 360 ) ,
w = scale ( parseFloat ( match [ 2 ] ) , 0 , 100 ) ,
b = scale ( parseFloat ( match [ 3 ] ) , 0 , 100 ) ,
a = scale ( isNaN ( alpha ) ? 1 : alpha , 0 , 1 ) ;
return [ h , w , b , a ] ;
}
}
function getRgb ( string ) {
var rgba = getRgba ( string ) ;
return rgba && rgba . slice ( 0 , 3 ) ;
}
function getHsl ( string ) {
var hsla = getHsla ( string ) ;
return hsla && hsla . slice ( 0 , 3 ) ;
}
function getAlpha ( string ) {
var vals = getRgba ( string ) ;
if ( vals ) {
return vals [ 3 ] ;
}
else if ( vals = getHsla ( string ) ) {
return vals [ 3 ] ;
}
else if ( vals = getHwb ( string ) ) {
return vals [ 3 ] ;
}
}
// generators
function hexString ( rgb ) {
return "#" + hexDouble ( rgb [ 0 ] ) + hexDouble ( rgb [ 1 ] )
+ hexDouble ( rgb [ 2 ] ) ;
}
function rgbString ( rgba , alpha ) {
if ( alpha < 1 || ( rgba [ 3 ] && rgba [ 3 ] < 1 ) ) {
return rgbaString ( rgba , alpha ) ;
}
return "rgb(" + rgba [ 0 ] + ", " + rgba [ 1 ] + ", " + rgba [ 2 ] + ")" ;
}
function rgbaString ( rgba , alpha ) {
if ( alpha === undefined ) {
alpha = ( rgba [ 3 ] !== undefined ? rgba [ 3 ] : 1 ) ;
}
return "rgba(" + rgba [ 0 ] + ", " + rgba [ 1 ] + ", " + rgba [ 2 ]
+ ", " + alpha + ")" ;
}
function percentString ( rgba , alpha ) {
if ( alpha < 1 || ( rgba [ 3 ] && rgba [ 3 ] < 1 ) ) {
return percentaString ( rgba , alpha ) ;
}
var r = Math . round ( rgba [ 0 ] / 255 * 100 ) ,
g = Math . round ( rgba [ 1 ] / 255 * 100 ) ,
b = Math . round ( rgba [ 2 ] / 255 * 100 ) ;
return "rgb(" + r + "%, " + g + "%, " + b + "%)" ;
}
function percentaString ( rgba , alpha ) {
var r = Math . round ( rgba [ 0 ] / 255 * 100 ) ,
g = Math . round ( rgba [ 1 ] / 255 * 100 ) ,
b = Math . round ( rgba [ 2 ] / 255 * 100 ) ;
return "rgba(" + r + "%, " + g + "%, " + b + "%, " + ( alpha || rgba [ 3 ] || 1 ) + ")" ;
}
function hslString ( hsla , alpha ) {
if ( alpha < 1 || ( hsla [ 3 ] && hsla [ 3 ] < 1 ) ) {
return hslaString ( hsla , alpha ) ;
}
return "hsl(" + hsla [ 0 ] + ", " + hsla [ 1 ] + "%, " + hsla [ 2 ] + "%)" ;
}
function hslaString ( hsla , alpha ) {
if ( alpha === undefined ) {
alpha = ( hsla [ 3 ] !== undefined ? hsla [ 3 ] : 1 ) ;
}
return "hsla(" + hsla [ 0 ] + ", " + hsla [ 1 ] + "%, " + hsla [ 2 ] + "%, "
+ alpha + ")" ;
}
// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
// (hwb have alpha optional & 1 is default value)
function hwbString ( hwb , alpha ) {
if ( alpha === undefined ) {
alpha = ( hwb [ 3 ] !== undefined ? hwb [ 3 ] : 1 ) ;
}
return "hwb(" + hwb [ 0 ] + ", " + hwb [ 1 ] + "%, " + hwb [ 2 ] + "%"
+ ( alpha !== undefined && alpha !== 1 ? ", " + alpha : "" ) + ")" ;
}
function keyword ( rgb ) {
return reverseNames [ rgb . slice ( 0 , 3 ) ] ;
}
// helpers
function scale ( num , min , max ) {
return Math . min ( Math . max ( min , num ) , max ) ;
}
function hexDouble ( num ) {
var str = num . toString ( 16 ) . toUpperCase ( ) ;
return ( str . length < 2 ) ? "0" + str : str ;
}
//create a list of reverse color names
var reverseNames = { } ;
for ( var name in colorNames ) {
reverseNames [ colorNames [ name ] ] = name ;
}
} , { "color-name" : 5 } ] , 2 : [ function ( require , module , exports ) {
/* MIT license */
var convert = require ( "color-convert" ) ,
string = require ( "chartjs-color-string" ) ;
var Color = function ( obj ) {
if ( obj instanceof Color ) return obj ;
if ( ! ( this instanceof Color ) ) return new Color ( obj ) ;
this . values = {
rgb : [ 0 , 0 , 0 ] ,
hsl : [ 0 , 0 , 0 ] ,
hsv : [ 0 , 0 , 0 ] ,
hwb : [ 0 , 0 , 0 ] ,
cmyk : [ 0 , 0 , 0 , 0 ] ,
alpha : 1
}
// parse Color() argument
if ( typeof obj == "string" ) {
var vals = string . getRgba ( obj ) ;
if ( vals ) {
this . setValues ( "rgb" , vals ) ;
} else if ( vals = string . getHsla ( obj ) ) {
this . setValues ( "hsl" , vals ) ;
} else if ( vals = string . getHwb ( obj ) ) {
this . setValues ( "hwb" , vals ) ;
} else {
throw new Error ( "Unable to parse color from string \"" + obj + "\"" ) ;
}
} else if ( typeof obj == "object" ) {
var vals = obj ;
if ( vals [ "r" ] !== undefined || vals [ "red" ] !== undefined ) {
this . setValues ( "rgb" , vals )
} else if ( vals [ "l" ] !== undefined || vals [ "lightness" ] !== undefined ) {
this . setValues ( "hsl" , vals )
} else if ( vals [ "v" ] !== undefined || vals [ "value" ] !== undefined ) {
this . setValues ( "hsv" , vals )
} else if ( vals [ "w" ] !== undefined || vals [ "whiteness" ] !== undefined ) {
this . setValues ( "hwb" , vals )
} else if ( vals [ "c" ] !== undefined || vals [ "cyan" ] !== undefined ) {
this . setValues ( "cmyk" , vals )
} else {
throw new Error ( "Unable to parse color from object " + JSON . stringify ( obj ) ) ;
}
}
}
Color . prototype = {
rgb : function ( vals ) {
return this . setSpace ( "rgb" , arguments ) ;
} ,
hsl : function ( vals ) {
return this . setSpace ( "hsl" , arguments ) ;
} ,
hsv : function ( vals ) {
return this . setSpace ( "hsv" , arguments ) ;
} ,
hwb : function ( vals ) {
return this . setSpace ( "hwb" , arguments ) ;
} ,
cmyk : function ( vals ) {
return this . setSpace ( "cmyk" , arguments ) ;
} ,
rgbArray : function ( ) {
return this . values . rgb ;
} ,
hslArray : function ( ) {
return this . values . hsl ;
} ,
hsvArray : function ( ) {
return this . values . hsv ;
} ,
hwbArray : function ( ) {
if ( this . values . alpha !== 1 ) {
return this . values . hwb . concat ( [ this . values . alpha ] )
}
return this . values . hwb ;
} ,
cmykArray : function ( ) {
return this . values . cmyk ;
} ,
rgbaArray : function ( ) {
var rgb = this . values . rgb ;
return rgb . concat ( [ this . values . alpha ] ) ;
} ,
hslaArray : function ( ) {
var hsl = this . values . hsl ;
return hsl . concat ( [ this . values . alpha ] ) ;
} ,
alpha : function ( val ) {
if ( val === undefined ) {
return this . values . alpha ;
}
this . setValues ( "alpha" , val ) ;
return this ;
} ,
red : function ( val ) {
return this . setChannel ( "rgb" , 0 , val ) ;
} ,
green : function ( val ) {
return this . setChannel ( "rgb" , 1 , val ) ;
} ,
blue : function ( val ) {
return this . setChannel ( "rgb" , 2 , val ) ;
} ,
hue : function ( val ) {
return this . setChannel ( "hsl" , 0 , val ) ;
} ,
saturation : function ( val ) {
return this . setChannel ( "hsl" , 1 , val ) ;
} ,
lightness : function ( val ) {
return this . setChannel ( "hsl" , 2 , val ) ;
} ,
saturationv : function ( val ) {
return this . setChannel ( "hsv" , 1 , val ) ;
} ,
whiteness : function ( val ) {
return this . setChannel ( "hwb" , 1 , val ) ;
} ,
blackness : function ( val ) {
return this . setChannel ( "hwb" , 2 , val ) ;
} ,
value : function ( val ) {
return this . setChannel ( "hsv" , 2 , val ) ;
} ,
cyan : function ( val ) {
return this . setChannel ( "cmyk" , 0 , val ) ;
} ,
magenta : function ( val ) {
return this . setChannel ( "cmyk" , 1 , val ) ;
} ,
yellow : function ( val ) {
return this . setChannel ( "cmyk" , 2 , val ) ;
} ,
black : function ( val ) {
return this . setChannel ( "cmyk" , 3 , val ) ;
} ,
hexString : function ( ) {
return string . hexString ( this . values . rgb ) ;
} ,
rgbString : function ( ) {
return string . rgbString ( this . values . rgb , this . values . alpha ) ;
} ,
rgbaString : function ( ) {
return string . rgbaString ( this . values . rgb , this . values . alpha ) ;
} ,
percentString : function ( ) {
return string . percentString ( this . values . rgb , this . values . alpha ) ;
} ,
hslString : function ( ) {
return string . hslString ( this . values . hsl , this . values . alpha ) ;
} ,
hslaString : function ( ) {
return string . hslaString ( this . values . hsl , this . values . alpha ) ;
} ,
hwbString : function ( ) {
return string . hwbString ( this . values . hwb , this . values . alpha ) ;
} ,
keyword : function ( ) {
return string . keyword ( this . values . rgb , this . values . alpha ) ;
} ,
rgbNumber : function ( ) {
return ( this . values . rgb [ 0 ] << 16 ) | ( this . values . rgb [ 1 ] << 8 ) | this . values . rgb [ 2 ] ;
} ,
luminosity : function ( ) {
// http://www.w3.org/TR/WCAG20/#relativeluminancedef
var rgb = this . values . rgb ;
var lum = [ ] ;
for ( var i = 0 ; i < rgb . length ; i ++ ) {
var chan = rgb [ i ] / 255 ;
lum [ i ] = ( chan <= 0.03928 ) ? chan / 12.92 : Math . pow ( ( ( chan + 0.055 ) / 1.055 ) , 2.4 )
}
return 0.2126 * lum [ 0 ] + 0.7152 * lum [ 1 ] + 0.0722 * lum [ 2 ] ;
} ,
contrast : function ( color2 ) {
// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
var lum1 = this . luminosity ( ) ;
var lum2 = color2 . luminosity ( ) ;
if ( lum1 > lum2 ) {
return ( lum1 + 0.05 ) / ( lum2 + 0.05 )
} ;
return ( lum2 + 0.05 ) / ( lum1 + 0.05 ) ;
} ,
level : function ( color2 ) {
var contrastRatio = this . contrast ( color2 ) ;
return ( contrastRatio >= 7.1 ) ? 'AAA' : ( contrastRatio >= 4.5 ) ? 'AA' : '' ;
} ,
dark : function ( ) {
// YIQ equation from http://24ways.org/2010/calculating-color-contrast
var rgb = this . values . rgb ,
yiq = ( rgb [ 0 ] * 299 + rgb [ 1 ] * 587 + rgb [ 2 ] * 114 ) / 1000 ;
return yiq < 128 ;
} ,
light : function ( ) {
return ! this . dark ( ) ;
} ,
negate : function ( ) {
var rgb = [ ]
for ( var i = 0 ; i < 3 ; i ++ ) {
rgb [ i ] = 255 - this . values . rgb [ i ] ;
}
this . setValues ( "rgb" , rgb ) ;
return this ;
} ,
lighten : function ( ratio ) {
this . values . hsl [ 2 ] += this . values . hsl [ 2 ] * ratio ;
this . setValues ( "hsl" , this . values . hsl ) ;
return this ;
} ,
darken : function ( ratio ) {
this . values . hsl [ 2 ] -= this . values . hsl [ 2 ] * ratio ;
this . setValues ( "hsl" , this . values . hsl ) ;
return this ;
} ,
saturate : function ( ratio ) {
this . values . hsl [ 1 ] += this . values . hsl [ 1 ] * ratio ;
this . setValues ( "hsl" , this . values . hsl ) ;
return this ;
} ,
desaturate : function ( ratio ) {
this . values . hsl [ 1 ] -= this . values . hsl [ 1 ] * ratio ;
this . setValues ( "hsl" , this . values . hsl ) ;
return this ;
} ,
whiten : function ( ratio ) {
this . values . hwb [ 1 ] += this . values . hwb [ 1 ] * ratio ;
this . setValues ( "hwb" , this . values . hwb ) ;
return this ;
} ,
blacken : function ( ratio ) {
this . values . hwb [ 2 ] += this . values . hwb [ 2 ] * ratio ;
this . setValues ( "hwb" , this . values . hwb ) ;
return this ;
} ,
greyscale : function ( ) {
var rgb = this . values . rgb ;
// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
var val = rgb [ 0 ] * 0.3 + rgb [ 1 ] * 0.59 + rgb [ 2 ] * 0.11 ;
this . setValues ( "rgb" , [ val , val , val ] ) ;
return this ;
} ,
clearer : function ( ratio ) {
this . setValues ( "alpha" , this . values . alpha - ( this . values . alpha * ratio ) ) ;
return this ;
} ,
opaquer : function ( ratio ) {
this . setValues ( "alpha" , this . values . alpha + ( this . values . alpha * ratio ) ) ;
return this ;
} ,
rotate : function ( degrees ) {
var hue = this . values . hsl [ 0 ] ;
hue = ( hue + degrees ) % 360 ;
hue = hue < 0 ? 360 + hue : hue ;
this . values . hsl [ 0 ] = hue ;
this . setValues ( "hsl" , this . values . hsl ) ;
return this ;
} ,
mix : function ( color2 , weight ) {
weight = 1 - ( weight == null ? 0.5 : weight ) ;
// algorithm from Sass's mix(). Ratio of first color in mix is
// determined by the alphas of both colors and the weight
var t1 = weight * 2 - 1 ,
d = this . alpha ( ) - color2 . alpha ( ) ;
var weight1 = ( ( ( t1 * d == - 1 ) ? t1 : ( t1 + d ) / ( 1 + t1 * d ) ) + 1 ) / 2 ;
var weight2 = 1 - weight1 ;
var rgb = this . rgbArray ( ) ;
var rgb2 = color2 . rgbArray ( ) ;
for ( var i = 0 ; i < rgb . length ; i ++ ) {
rgb [ i ] = rgb [ i ] * weight1 + rgb2 [ i ] * weight2 ;
}
this . setValues ( "rgb" , rgb ) ;
var alpha = this . alpha ( ) * weight + color2 . alpha ( ) * ( 1 - weight ) ;
this . setValues ( "alpha" , alpha ) ;
return this ;
} ,
toJSON : function ( ) {
return this . rgb ( ) ;
} ,
clone : function ( ) {
return new Color ( this . rgb ( ) ) ;
}
}
Color . prototype . getValues = function ( space ) {
var vals = { } ;
for ( var i = 0 ; i < space . length ; i ++ ) {
vals [ space . charAt ( i ) ] = this . values [ space ] [ i ] ;
}
if ( this . values . alpha != 1 ) {
vals [ "a" ] = this . values . alpha ;
}
// {r: 255, g: 255, b: 255, a: 0.4}
return vals ;
}
Color . prototype . setValues = function ( space , vals ) {
var spaces = {
"rgb" : [ "red" , "green" , "blue" ] ,
"hsl" : [ "hue" , "saturation" , "lightness" ] ,
"hsv" : [ "hue" , "saturation" , "value" ] ,
"hwb" : [ "hue" , "whiteness" , "blackness" ] ,
"cmyk" : [ "cyan" , "magenta" , "yellow" , "black" ]
} ;
var maxes = {
"rgb" : [ 255 , 255 , 255 ] ,
"hsl" : [ 360 , 100 , 100 ] ,
"hsv" : [ 360 , 100 , 100 ] ,
"hwb" : [ 360 , 100 , 100 ] ,
"cmyk" : [ 100 , 100 , 100 , 100 ]
} ;
var alpha = 1 ;
if ( space == "alpha" ) {
alpha = vals ;
} else if ( vals . length ) {
// [10, 10, 10]
this . values [ space ] = vals . slice ( 0 , space . length ) ;
alpha = vals [ space . length ] ;
} else if ( vals [ space . charAt ( 0 ) ] !== undefined ) {
// {r: 10, g: 10, b: 10}
for ( var i = 0 ; i < space . length ; i ++ ) {
this . values [ space ] [ i ] = vals [ space . charAt ( i ) ] ;
}
alpha = vals . a ;
} else if ( vals [ spaces [ space ] [ 0 ] ] !== undefined ) {
// {red: 10, green: 10, blue: 10}
var chans = spaces [ space ] ;
for ( var i = 0 ; i < space . length ; i ++ ) {
this . values [ space ] [ i ] = vals [ chans [ i ] ] ;
}
alpha = vals . alpha ;
}
this . values . alpha = Math . max ( 0 , Math . min ( 1 , ( alpha !== undefined ? alpha : this . values . alpha ) ) ) ;
if ( space == "alpha" ) {
return ;
}
// cap values of the space prior converting all values
for ( var i = 0 ; i < space . length ; i ++ ) {
var capped = Math . max ( 0 , Math . min ( maxes [ space ] [ i ] , this . values [ space ] [ i ] ) ) ;
this . values [ space ] [ i ] = Math . round ( capped ) ;
}
// convert to all the other color spaces
for ( var sname in spaces ) {
if ( sname != space ) {
this . values [ sname ] = convert [ space ] [ sname ] ( this . values [ space ] )
}
// cap values
for ( var i = 0 ; i < sname . length ; i ++ ) {
var capped = Math . max ( 0 , Math . min ( maxes [ sname ] [ i ] , this . values [ sname ] [ i ] ) ) ;
this . values [ sname ] [ i ] = Math . round ( capped ) ;
}
}
return true ;
}
Color . prototype . setSpace = function ( space , args ) {
var vals = args [ 0 ] ;
if ( vals === undefined ) {
// color.rgb()
return this . getValues ( space ) ;
}
// color.rgb(10, 10, 10)
if ( typeof vals == "number" ) {
vals = Array . prototype . slice . call ( args ) ;
}
this . setValues ( space , vals ) ;
return this ;
}
Color . prototype . setChannel = function ( space , index , val ) {
if ( val === undefined ) {
// color.red()
return this . values [ space ] [ index ] ;
}
// color.red(100)
this . values [ space ] [ index ] = val ;
this . setValues ( space , this . values [ space ] ) ;
return this ;
}
window . Color = module . exports = Color
} , { "chartjs-color-string" : 1 , "color-convert" : 4 } ] , 3 : [ function ( require , module , exports ) {
/* MIT license */
module . exports = {
rgb2hsl : rgb2hsl ,
rgb2hsv : rgb2hsv ,
rgb2hwb : rgb2hwb ,
rgb2cmyk : rgb2cmyk ,
rgb2keyword : rgb2keyword ,
rgb2xyz : rgb2xyz ,
rgb2lab : rgb2lab ,
rgb2lch : rgb2lch ,
hsl2rgb : hsl2rgb ,
hsl2hsv : hsl2hsv ,
hsl2hwb : hsl2hwb ,
hsl2cmyk : hsl2cmyk ,
hsl2keyword : hsl2keyword ,
hsv2rgb : hsv2rgb ,
hsv2hsl : hsv2hsl ,
hsv2hwb : hsv2hwb ,
hsv2cmyk : hsv2cmyk ,
hsv2keyword : hsv2keyword ,
hwb2rgb : hwb2rgb ,
hwb2hsl : hwb2hsl ,
hwb2hsv : hwb2hsv ,
hwb2cmyk : hwb2cmyk ,
hwb2keyword : hwb2keyword ,
cmyk2rgb : cmyk2rgb ,
cmyk2hsl : cmyk2hsl ,
cmyk2hsv : cmyk2hsv ,
cmyk2hwb : cmyk2hwb ,
cmyk2keyword : cmyk2keyword ,
keyword2rgb : keyword2rgb ,
keyword2hsl : keyword2hsl ,
keyword2hsv : keyword2hsv ,
keyword2hwb : keyword2hwb ,
keyword2cmyk : keyword2cmyk ,
keyword2lab : keyword2lab ,
keyword2xyz : keyword2xyz ,
xyz2rgb : xyz2rgb ,
xyz2lab : xyz2lab ,
xyz2lch : xyz2lch ,
lab2xyz : lab2xyz ,
lab2rgb : lab2rgb ,
lab2lch : lab2lch ,
lch2lab : lch2lab ,
lch2xyz : lch2xyz ,
lch2rgb : lch2rgb
}
function rgb2hsl ( rgb ) {
var r = rgb [ 0 ] / 255 ,
g = rgb [ 1 ] / 255 ,
b = rgb [ 2 ] / 255 ,
min = Math . min ( r , g , b ) ,
max = Math . max ( r , g , b ) ,
delta = max - min ,
h , s , l ;
if ( max == min )
h = 0 ;
else if ( r == max )
h = ( g - b ) / delta ;
else if ( g == max )
h = 2 + ( b - r ) / delta ;
else if ( b == max )
h = 4 + ( r - g ) / delta ;
h = Math . min ( h * 60 , 360 ) ;
if ( h < 0 )
h += 360 ;
l = ( min + max ) / 2 ;
if ( max == min )
s = 0 ;
else if ( l <= 0.5 )
s = delta / ( max + min ) ;
else
s = delta / ( 2 - max - min ) ;
return [ h , s * 100 , l * 100 ] ;
}
function rgb2hsv ( rgb ) {
var r = rgb [ 0 ] ,
g = rgb [ 1 ] ,
b = rgb [ 2 ] ,
min = Math . min ( r , g , b ) ,
max = Math . max ( r , g , b ) ,
delta = max - min ,
h , s , v ;
if ( max == 0 )
s = 0 ;
else
s = ( delta / max * 1000 ) / 10 ;
if ( max == min )
h = 0 ;
else if ( r == max )
h = ( g - b ) / delta ;
else if ( g == max )
h = 2 + ( b - r ) / delta ;
else if ( b == max )
h = 4 + ( r - g ) / delta ;
h = Math . min ( h * 60 , 360 ) ;
if ( h < 0 )
h += 360 ;
v = ( ( max / 255 ) * 1000 ) / 10 ;
return [ h , s , v ] ;
}
function rgb2hwb ( rgb ) {
var r = rgb [ 0 ] ,
g = rgb [ 1 ] ,
b = rgb [ 2 ] ,
h = rgb2hsl ( rgb ) [ 0 ] ,
w = 1 / 255 * Math . min ( r , Math . min ( g , b ) ) ,
b = 1 - 1 / 255 * Math . max ( r , Math . max ( g , b ) ) ;
return [ h , w * 100 , b * 100 ] ;
}
function rgb2cmyk ( rgb ) {
var r = rgb [ 0 ] / 255 ,
g = rgb [ 1 ] / 255 ,
b = rgb [ 2 ] / 255 ,
c , m , y , k ;
k = Math . min ( 1 - r , 1 - g , 1 - b ) ;
c = ( 1 - r - k ) / ( 1 - k ) || 0 ;
m = ( 1 - g - k ) / ( 1 - k ) || 0 ;
y = ( 1 - b - k ) / ( 1 - k ) || 0 ;
return [ c * 100 , m * 100 , y * 100 , k * 100 ] ;
}
function rgb2keyword ( rgb ) {
return reverseKeywords [ JSON . stringify ( rgb ) ] ;
}
function rgb2xyz ( rgb ) {
var r = rgb [ 0 ] / 255 ,
g = rgb [ 1 ] / 255 ,
b = rgb [ 2 ] / 255 ;
// assume sRGB
r = r > 0.04045 ? Math . pow ( ( ( r + 0.055 ) / 1.055 ) , 2.4 ) : ( r / 12.92 ) ;
g = g > 0.04045 ? Math . pow ( ( ( g + 0.055 ) / 1.055 ) , 2.4 ) : ( g / 12.92 ) ;
b = b > 0.04045 ? Math . pow ( ( ( b + 0.055 ) / 1.055 ) , 2.4 ) : ( b / 12.92 ) ;
var x = ( r * 0.4124 ) + ( g * 0.3576 ) + ( b * 0.1805 ) ;
var y = ( r * 0.2126 ) + ( g * 0.7152 ) + ( b * 0.0722 ) ;
var z = ( r * 0.0193 ) + ( g * 0.1192 ) + ( b * 0.9505 ) ;
return [ x * 100 , y * 100 , z * 100 ] ;
}
function rgb2lab ( rgb ) {
var xyz = rgb2xyz ( rgb ) ,
x = xyz [ 0 ] ,
y = xyz [ 1 ] ,
z = xyz [ 2 ] ,
l , a , b ;
x /= 95.047 ;
y /= 100 ;
z /= 108.883 ;
x = x > 0.008856 ? Math . pow ( x , 1 / 3 ) : ( 7.787 * x ) + ( 16 / 116 ) ;
y = y > 0.008856 ? Math . pow ( y , 1 / 3 ) : ( 7.787 * y ) + ( 16 / 116 ) ;
z = z > 0.008856 ? Math . pow ( z , 1 / 3 ) : ( 7.787 * z ) + ( 16 / 116 ) ;
l = ( 116 * y ) - 16 ;
a = 500 * ( x - y ) ;
b = 200 * ( y - z ) ;
return [ l , a , b ] ;
}
function rgb2lch ( args ) {
return lab2lch ( rgb2lab ( args ) ) ;
}
function hsl2rgb ( hsl ) {
var h = hsl [ 0 ] / 360 ,
s = hsl [ 1 ] / 100 ,
l = hsl [ 2 ] / 100 ,
t1 , t2 , t3 , rgb , val ;
if ( s == 0 ) {
val = l * 255 ;
return [ val , val , val ] ;
}
if ( l < 0.5 )
t2 = l * ( 1 + s ) ;
else
t2 = l + s - l * s ;
t1 = 2 * l - t2 ;
rgb = [ 0 , 0 , 0 ] ;
for ( var i = 0 ; i < 3 ; i ++ ) {
t3 = h + 1 / 3 * - ( i - 1 ) ;
t3 < 0 && t3 ++ ;
t3 > 1 && t3 -- ;
if ( 6 * t3 < 1 )
val = t1 + ( t2 - t1 ) * 6 * t3 ;
else if ( 2 * t3 < 1 )
val = t2 ;
else if ( 3 * t3 < 2 )
val = t1 + ( t2 - t1 ) * ( 2 / 3 - t3 ) * 6 ;
else
val = t1 ;
rgb [ i ] = val * 255 ;
}
return rgb ;
}
function hsl2hsv ( hsl ) {
var h = hsl [ 0 ] ,
s = hsl [ 1 ] / 100 ,
l = hsl [ 2 ] / 100 ,
sv , v ;
if ( l === 0 ) {
// no need to do calc on black
// also avoids divide by 0 error
return [ 0 , 0 , 0 ] ;
}
l *= 2 ;
s *= ( l <= 1 ) ? l : 2 - l ;
v = ( l + s ) / 2 ;
sv = ( 2 * s ) / ( l + s ) ;
return [ h , sv * 100 , v * 100 ] ;
}
function hsl2hwb ( args ) {
return rgb2hwb ( hsl2rgb ( args ) ) ;
}
function hsl2cmyk ( args ) {
return rgb2cmyk ( hsl2rgb ( args ) ) ;
}
function hsl2keyword ( args ) {
return rgb2keyword ( hsl2rgb ( args ) ) ;
}
function hsv2rgb ( hsv ) {
var h = hsv [ 0 ] / 60 ,
s = hsv [ 1 ] / 100 ,
v = hsv [ 2 ] / 100 ,
hi = Math . floor ( h ) % 6 ;
var f = h - Math . floor ( h ) ,
p = 255 * v * ( 1 - s ) ,
q = 255 * v * ( 1 - ( s * f ) ) ,
t = 255 * v * ( 1 - ( s * ( 1 - f ) ) ) ,
v = 255 * v ;
switch ( hi ) {
case 0 :
return [ v , t , p ] ;
case 1 :
return [ q , v , p ] ;
case 2 :
return [ p , v , t ] ;
case 3 :
return [ p , q , v ] ;
case 4 :
return [ t , p , v ] ;
case 5 :
return [ v , p , q ] ;
}
}
function hsv2hsl ( hsv ) {
var h = hsv [ 0 ] ,
s = hsv [ 1 ] / 100 ,
v = hsv [ 2 ] / 100 ,
sl , l ;
l = ( 2 - s ) * v ;
sl = s * v ;
sl /= ( l <= 1 ) ? l : 2 - l ;
sl = sl || 0 ;
l /= 2 ;
return [ h , sl * 100 , l * 100 ] ;
}
function hsv2hwb ( args ) {
return rgb2hwb ( hsv2rgb ( args ) )
}
function hsv2cmyk ( args ) {
return rgb2cmyk ( hsv2rgb ( args ) ) ;
}
function hsv2keyword ( args ) {
return rgb2keyword ( hsv2rgb ( args ) ) ;
}
// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
function hwb2rgb ( hwb ) {
var h = hwb [ 0 ] / 360 ,
wh = hwb [ 1 ] / 100 ,
bl = hwb [ 2 ] / 100 ,
ratio = wh + bl ,
i , v , f , n ;
// wh + bl cant be > 1
if ( ratio > 1 ) {
wh /= ratio ;
bl /= ratio ;
}
i = Math . floor ( 6 * h ) ;
v = 1 - bl ;
f = 6 * h - i ;
if ( ( i & 0x01 ) != 0 ) {
f = 1 - f ;
}
n = wh + f * ( v - wh ) ; // linear interpolation
switch ( i ) {
default :
case 6 :
case 0 : r = v ; g = n ; b = wh ; break ;
case 1 : r = n ; g = v ; b = wh ; break ;
case 2 : r = wh ; g = v ; b = n ; break ;
case 3 : r = wh ; g = n ; b = v ; break ;
case 4 : r = n ; g = wh ; b = v ; break ;
case 5 : r = v ; g = wh ; b = n ; break ;
}
return [ r * 255 , g * 255 , b * 255 ] ;
}
function hwb2hsl ( args ) {
return rgb2hsl ( hwb2rgb ( args ) ) ;
}
function hwb2hsv ( args ) {
return rgb2hsv ( hwb2rgb ( args ) ) ;
}
function hwb2cmyk ( args ) {
return rgb2cmyk ( hwb2rgb ( args ) ) ;
}
function hwb2keyword ( args ) {
return rgb2keyword ( hwb2rgb ( args ) ) ;
}
function cmyk2rgb ( cmyk ) {
var c = cmyk [ 0 ] / 100 ,
m = cmyk [ 1 ] / 100 ,
y = cmyk [ 2 ] / 100 ,
k = cmyk [ 3 ] / 100 ,
r , g , b ;
r = 1 - Math . min ( 1 , c * ( 1 - k ) + k ) ;
g = 1 - Math . min ( 1 , m * ( 1 - k ) + k ) ;
b = 1 - Math . min ( 1 , y * ( 1 - k ) + k ) ;
return [ r * 255 , g * 255 , b * 255 ] ;
}
function cmyk2hsl ( args ) {
return rgb2hsl ( cmyk2rgb ( args ) ) ;
}
function cmyk2hsv ( args ) {
return rgb2hsv ( cmyk2rgb ( args ) ) ;
}
function cmyk2hwb ( args ) {
return rgb2hwb ( cmyk2rgb ( args ) ) ;
}
function cmyk2keyword ( args ) {
return rgb2keyword ( cmyk2rgb ( args ) ) ;
}
function xyz2rgb ( xyz ) {
var x = xyz [ 0 ] / 100 ,
y = xyz [ 1 ] / 100 ,
z = xyz [ 2 ] / 100 ,
r , g , b ;
r = ( x * 3.2406 ) + ( y * - 1.5372 ) + ( z * - 0.4986 ) ;
g = ( x * - 0.9689 ) + ( y * 1.8758 ) + ( z * 0.0415 ) ;
b = ( x * 0.0557 ) + ( y * - 0.2040 ) + ( z * 1.0570 ) ;
// assume sRGB
r = r > 0.0031308 ? ( ( 1.055 * Math . pow ( r , 1.0 / 2.4 ) ) - 0.055 )
: r = ( r * 12.92 ) ;
g = g > 0.0031308 ? ( ( 1.055 * Math . pow ( g , 1.0 / 2.4 ) ) - 0.055 )
: g = ( g * 12.92 ) ;
b = b > 0.0031308 ? ( ( 1.055 * Math . pow ( b , 1.0 / 2.4 ) ) - 0.055 )
: b = ( b * 12.92 ) ;
r = Math . min ( Math . max ( 0 , r ) , 1 ) ;
g = Math . min ( Math . max ( 0 , g ) , 1 ) ;
b = Math . min ( Math . max ( 0 , b ) , 1 ) ;
return [ r * 255 , g * 255 , b * 255 ] ;
}
function xyz2lab ( xyz ) {
var x = xyz [ 0 ] ,
y = xyz [ 1 ] ,
z = xyz [ 2 ] ,
l , a , b ;
x /= 95.047 ;
y /= 100 ;
z /= 108.883 ;
x = x > 0.008856 ? Math . pow ( x , 1 / 3 ) : ( 7.787 * x ) + ( 16 / 116 ) ;
y = y > 0.008856 ? Math . pow ( y , 1 / 3 ) : ( 7.787 * y ) + ( 16 / 116 ) ;
z = z > 0.008856 ? Math . pow ( z , 1 / 3 ) : ( 7.787 * z ) + ( 16 / 116 ) ;
l = ( 116 * y ) - 16 ;
a = 500 * ( x - y ) ;
b = 200 * ( y - z ) ;
return [ l , a , b ] ;
}
function xyz2lch ( args ) {
return lab2lch ( xyz2lab ( args ) ) ;
}
function lab2xyz ( lab ) {
var l = lab [ 0 ] ,
a = lab [ 1 ] ,
b = lab [ 2 ] ,
x , y , z , y2 ;
if ( l <= 8 ) {
y = ( l * 100 ) / 903.3 ;
y2 = ( 7.787 * ( y / 100 ) ) + ( 16 / 116 ) ;
} else {
y = 100 * Math . pow ( ( l + 16 ) / 116 , 3 ) ;
y2 = Math . pow ( y / 100 , 1 / 3 ) ;
}
x = x / 95.047 <= 0.008856 ? x = ( 95.047 * ( ( a / 500 ) + y2 - ( 16 / 116 ) ) ) / 7.787 : 95.047 * Math . pow ( ( a / 500 ) + y2 , 3 ) ;
z = z / 108.883 <= 0.008859 ? z = ( 108.883 * ( y2 - ( b / 200 ) - ( 16 / 116 ) ) ) / 7.787 : 108.883 * Math . pow ( y2 - ( b / 200 ) , 3 ) ;
return [ x , y , z ] ;
}
function lab2lch ( lab ) {
var l = lab [ 0 ] ,
a = lab [ 1 ] ,
b = lab [ 2 ] ,
hr , h , c ;
hr = Math . atan2 ( b , a ) ;
h = hr * 360 / 2 / Math . PI ;
if ( h < 0 ) {
h += 360 ;
}
c = Math . sqrt ( a * a + b * b ) ;
return [ l , c , h ] ;
}
function lab2rgb ( args ) {
return xyz2rgb ( lab2xyz ( args ) ) ;
}
function lch2lab ( lch ) {
var l = lch [ 0 ] ,
c = lch [ 1 ] ,
h = lch [ 2 ] ,
a , b , hr ;
hr = h / 360 * 2 * Math . PI ;
a = c * Math . cos ( hr ) ;
b = c * Math . sin ( hr ) ;
return [ l , a , b ] ;
}
function lch2xyz ( args ) {
return lab2xyz ( lch2lab ( args ) ) ;
}
function lch2rgb ( args ) {
return lab2rgb ( lch2lab ( args ) ) ;
}
function keyword2rgb ( keyword ) {
return cssKeywords [ keyword ] ;
}
function keyword2hsl ( args ) {
return rgb2hsl ( keyword2rgb ( args ) ) ;
}
function keyword2hsv ( args ) {
return rgb2hsv ( keyword2rgb ( args ) ) ;
}
function keyword2hwb ( args ) {
return rgb2hwb ( keyword2rgb ( args ) ) ;
}
function keyword2cmyk ( args ) {
return rgb2cmyk ( keyword2rgb ( args ) ) ;
}
function keyword2lab ( args ) {
return rgb2lab ( keyword2rgb ( args ) ) ;
}
function keyword2xyz ( args ) {
return rgb2xyz ( keyword2rgb ( args ) ) ;
}
var cssKeywords = {
aliceblue : [ 240 , 248 , 255 ] ,
antiquewhite : [ 250 , 235 , 215 ] ,
aqua : [ 0 , 255 , 255 ] ,
aquamarine : [ 127 , 255 , 212 ] ,
azure : [ 240 , 255 , 255 ] ,
beige : [ 245 , 245 , 220 ] ,
bisque : [ 255 , 228 , 196 ] ,
black : [ 0 , 0 , 0 ] ,
blanchedalmond : [ 255 , 235 , 205 ] ,
blue : [ 0 , 0 , 255 ] ,
blueviolet : [ 138 , 43 , 226 ] ,
brown : [ 165 , 42 , 42 ] ,
burlywood : [ 222 , 184 , 135 ] ,
cadetblue : [ 95 , 158 , 160 ] ,
chartreuse : [ 127 , 255 , 0 ] ,
chocolate : [ 210 , 105 , 30 ] ,
coral : [ 255 , 127 , 80 ] ,
cornflowerblue : [ 100 , 149 , 237 ] ,
cornsilk : [ 255 , 248 , 220 ] ,
crimson : [ 220 , 20 , 60 ] ,
cyan : [ 0 , 255 , 255 ] ,
darkblue : [ 0 , 0 , 139 ] ,
darkcyan : [ 0 , 139 , 139 ] ,
darkgoldenrod : [ 184 , 134 , 11 ] ,
darkgray : [ 169 , 169 , 169 ] ,
darkgreen : [ 0 , 100 , 0 ] ,
darkgrey : [ 169 , 169 , 169 ] ,
darkkhaki : [ 189 , 183 , 107 ] ,
darkmagenta : [ 139 , 0 , 139 ] ,
darkolivegreen : [ 85 , 107 , 47 ] ,
darkorange : [ 255 , 140 , 0 ] ,
darkorchid : [ 153 , 50 , 204 ] ,
darkred : [ 139 , 0 , 0 ] ,
darksalmon : [ 233 , 150 , 122 ] ,
darkseagreen : [ 143 , 188 , 143 ] ,
darkslateblue : [ 72 , 61 , 139 ] ,
darkslategray : [ 47 , 79 , 79 ] ,
darkslategrey : [ 47 , 79 , 79 ] ,
darkturquoise : [ 0 , 206 , 209 ] ,
darkviolet : [ 148 , 0 , 211 ] ,
deeppink : [ 255 , 20 , 147 ] ,
deepskyblue : [ 0 , 191 , 255 ] ,
dimgray : [ 105 , 105 , 105 ] ,
dimgrey : [ 105 , 105 , 105 ] ,
dodgerblue : [ 30 , 144 , 255 ] ,
firebrick : [ 178 , 34 , 34 ] ,
floralwhite : [ 255 , 250 , 240 ] ,
forestgreen : [ 34 , 139 , 34 ] ,
fuchsia : [ 255 , 0 , 255 ] ,
gainsboro : [ 220 , 220 , 220 ] ,
ghostwhite : [ 248 , 248 , 255 ] ,
gold : [ 255 , 215 , 0 ] ,
goldenrod : [ 218 , 165 , 32 ] ,
gray : [ 128 , 128 , 128 ] ,
green : [ 0 , 128 , 0 ] ,
greenyellow : [ 173 , 255 , 47 ] ,
grey : [ 128 , 128 , 128 ] ,
honeydew : [ 240 , 255 , 240 ] ,
hotpink : [ 255 , 105 , 180 ] ,
indianred : [ 205 , 92 , 92 ] ,
indigo : [ 75 , 0 , 130 ] ,
ivory : [ 255 , 255 , 240 ] ,
khaki : [ 240 , 230 , 140 ] ,
lavender : [ 230 , 230 , 250 ] ,
lavenderblush : [ 255 , 240 , 245 ] ,
lawngreen : [ 124 , 252 , 0 ] ,
lemonchiffon : [ 255 , 250 , 205 ] ,
lightblue : [ 173 , 216 , 230 ] ,
lightcoral : [ 240 , 128 , 128 ] ,
lightcyan : [ 224 , 255 , 255 ] ,
lightgoldenrodyellow : [ 250 , 250 , 210 ] ,
lightgray : [ 211 , 211 , 211 ] ,
lightgreen : [ 144 , 238 , 144 ] ,
lightgrey : [ 211 , 211 , 211 ] ,
lightpink : [ 255 , 182 , 193 ] ,
lightsalmon : [ 255 , 160 , 122 ] ,
lightseagreen : [ 32 , 178 , 170 ] ,
lightskyblue : [ 135 , 206 , 250 ] ,
lightslategray : [ 119 , 136 , 153 ] ,
lightslategrey : [ 119 , 136 , 153 ] ,
lightsteelblue : [ 176 , 196 , 222 ] ,
lightyellow : [ 255 , 255 , 224 ] ,
lime : [ 0 , 255 , 0 ] ,
limegreen : [ 50 , 205 , 50 ] ,
linen : [ 250 , 240 , 230 ] ,
magenta : [ 255 , 0 , 255 ] ,
maroon : [ 128 , 0 , 0 ] ,
mediumaquamarine : [ 102 , 205 , 170 ] ,
mediumblue : [ 0 , 0 , 205 ] ,
mediumorchid : [ 186 , 85 , 211 ] ,
mediumpurple : [ 147 , 112 , 219 ] ,
mediumseagreen : [ 60 , 179 , 113 ] ,
mediumslateblue : [ 123 , 104 , 238 ] ,
mediumspringgreen : [ 0 , 250 , 154 ] ,
mediumturquoise : [ 72 , 209 , 204 ] ,
mediumvioletred : [ 199 , 21 , 133 ] ,
midnightblue : [ 25 , 25 , 112 ] ,
mintcream : [ 245 , 255 , 250 ] ,
mistyrose : [ 255 , 228 , 225 ] ,
moccasin : [ 255 , 228 , 181 ] ,
navajowhite : [ 255 , 222 , 173 ] ,
navy : [ 0 , 0 , 128 ] ,
oldlace : [ 253 , 245 , 230 ] ,
olive : [ 128 , 128 , 0 ] ,
olivedrab : [ 107 , 142 , 35 ] ,
orange : [ 255 , 165 , 0 ] ,
orangered : [ 255 , 69 , 0 ] ,
orchid : [ 218 , 112 , 214 ] ,
palegoldenrod : [ 238 , 232 , 170 ] ,
palegreen : [ 152 , 251 , 152 ] ,
paleturquoise : [ 175 , 238 , 238 ] ,
palevioletred : [ 219 , 112 , 147 ] ,
papayawhip : [ 255 , 239 , 213 ] ,
peachpuff : [ 255 , 218 , 185 ] ,
peru : [ 205 , 133 , 63 ] ,
pink : [ 255 , 192 , 203 ] ,
plum : [ 221 , 160 , 221 ] ,
powderblue : [ 176 , 224 , 230 ] ,
purple : [ 128 , 0 , 128 ] ,
rebeccapurple : [ 102 , 51 , 153 ] ,
red : [ 255 , 0 , 0 ] ,
rosybrown : [ 188 , 143 , 143 ] ,
royalblue : [ 65 , 105 , 225 ] ,
saddlebrown : [ 139 , 69 , 19 ] ,
salmon : [ 250 , 128 , 114 ] ,
sandybrown : [ 244 , 164 , 96 ] ,
seagreen : [ 46 , 139 , 87 ] ,
seashell : [ 255 , 245 , 238 ] ,
sienna : [ 160 , 82 , 45 ] ,
silver : [ 192 , 192 , 192 ] ,
skyblue : [ 135 , 206 , 235 ] ,
slateblue : [ 106 , 90 , 205 ] ,
slategray : [ 112 , 128 , 144 ] ,
slategrey : [ 112 , 128 , 144 ] ,
snow : [ 255 , 250 , 250 ] ,
springgreen : [ 0 , 255 , 127 ] ,
steelblue : [ 70 , 130 , 180 ] ,
tan : [ 210 , 180 , 140 ] ,
teal : [ 0 , 128 , 128 ] ,
thistle : [ 216 , 191 , 216 ] ,
tomato : [ 255 , 99 , 71 ] ,
turquoise : [ 64 , 224 , 208 ] ,
violet : [ 238 , 130 , 238 ] ,
wheat : [ 245 , 222 , 179 ] ,
white : [ 255 , 255 , 255 ] ,
whitesmoke : [ 245 , 245 , 245 ] ,
yellow : [ 255 , 255 , 0 ] ,
yellowgreen : [ 154 , 205 , 50 ]
} ;
var reverseKeywords = { } ;
for ( var key in cssKeywords ) {
reverseKeywords [ JSON . stringify ( cssKeywords [ key ] ) ] = key ;
}
} , { } ] , 4 : [ function ( require , module , exports ) {
var conversions = require ( "./conversions" ) ;
var convert = function ( ) {
return new Converter ( ) ;
}
for ( var func in conversions ) {
// export Raw versions
convert [ func + "Raw" ] = ( function ( func ) {
// accept array or plain args
return function ( arg ) {
if ( typeof arg == "number" )
arg = Array . prototype . slice . call ( arguments ) ;
return conversions [ func ] ( arg ) ;
}
} ) ( func ) ;
var pair = /(\w+)2(\w+)/ . exec ( func ) ,
from = pair [ 1 ] ,
to = pair [ 2 ] ;
// export rgb2hsl and ["rgb"]["hsl"]
convert [ from ] = convert [ from ] || { } ;
convert [ from ] [ to ] = convert [ func ] = ( function ( func ) {
return function ( arg ) {
if ( typeof arg == "number" )
arg = Array . prototype . slice . call ( arguments ) ;
var val = conversions [ func ] ( arg ) ;
if ( typeof val == "string" || val === undefined )
return val ; // keyword
for ( var i = 0 ; i < val . length ; i ++ )
val [ i ] = Math . round ( val [ i ] ) ;
return val ;
}
} ) ( func ) ;
}
/* Converter does lazy conversion and caching */
var Converter = function ( ) {
this . convs = { } ;
} ;
/ * E i t h e r g e t t h e v a l u e s f o r a s p a c e o r
set the values for a space , depending on args * /
Converter . prototype . routeSpace = function ( space , args ) {
var values = args [ 0 ] ;
if ( values === undefined ) {
// color.rgb()
return this . getValues ( space ) ;
}
// color.rgb(10, 10, 10)
if ( typeof values == "number" ) {
values = Array . prototype . slice . call ( args ) ;
}
return this . setValues ( space , values ) ;
} ;
/* Set the values for a space, invalidating cache */
Converter . prototype . setValues = function ( space , values ) {
this . space = space ;
this . convs = { } ;
this . convs [ space ] = values ;
return this ;
} ;
/ * G e t t h e v a l u e s f o r a s p a c e . I f t h e r e ' s a l r e a d y
a conversion for the space , fetch it , otherwise
compute it * /
Converter . prototype . getValues = function ( space ) {
var vals = this . convs [ space ] ;
if ( ! vals ) {
var fspace = this . space ,
from = this . convs [ fspace ] ;
vals = convert [ fspace ] [ space ] ( from ) ;
this . convs [ space ] = vals ;
}
return vals ;
} ;
[ "rgb" , "hsl" , "hsv" , "cmyk" , "keyword" ] . forEach ( function ( space ) {
Converter . prototype [ space ] = function ( vals ) {
return this . routeSpace ( space , arguments ) ;
}
} ) ;
module . exports = convert ;
} , { "./conversions" : 3 } ] , 5 : [ function ( require , module , exports ) {
module . exports = {
"aliceblue" : [ 240 , 248 , 255 ] ,
"antiquewhite" : [ 250 , 235 , 215 ] ,
"aqua" : [ 0 , 255 , 255 ] ,
"aquamarine" : [ 127 , 255 , 212 ] ,
"azure" : [ 240 , 255 , 255 ] ,
"beige" : [ 245 , 245 , 220 ] ,
"bisque" : [ 255 , 228 , 196 ] ,
"black" : [ 0 , 0 , 0 ] ,
"blanchedalmond" : [ 255 , 235 , 205 ] ,
"blue" : [ 0 , 0 , 255 ] ,
"blueviolet" : [ 138 , 43 , 226 ] ,
"brown" : [ 165 , 42 , 42 ] ,
"burlywood" : [ 222 , 184 , 135 ] ,
"cadetblue" : [ 95 , 158 , 160 ] ,
"chartreuse" : [ 127 , 255 , 0 ] ,
"chocolate" : [ 210 , 105 , 30 ] ,
"coral" : [ 255 , 127 , 80 ] ,
"cornflowerblue" : [ 100 , 149 , 237 ] ,
"cornsilk" : [ 255 , 248 , 220 ] ,
"crimson" : [ 220 , 20 , 60 ] ,
"cyan" : [ 0 , 255 , 255 ] ,
"darkblue" : [ 0 , 0 , 139 ] ,
"darkcyan" : [ 0 , 139 , 139 ] ,
"darkgoldenrod" : [ 184 , 134 , 11 ] ,
"darkgray" : [ 169 , 169 , 169 ] ,
"darkgreen" : [ 0 , 100 , 0 ] ,
"darkgrey" : [ 169 , 169 , 169 ] ,
"darkkhaki" : [ 189 , 183 , 107 ] ,
"darkmagenta" : [ 139 , 0 , 139 ] ,
"darkolivegreen" : [ 85 , 107 , 47 ] ,
"darkorange" : [ 255 , 140 , 0 ] ,
"darkorchid" : [ 153 , 50 , 204 ] ,
"darkred" : [ 139 , 0 , 0 ] ,
"darksalmon" : [ 233 , 150 , 122 ] ,
"darkseagreen" : [ 143 , 188 , 143 ] ,
"darkslateblue" : [ 72 , 61 , 139 ] ,
"darkslategray" : [ 47 , 79 , 79 ] ,
"darkslategrey" : [ 47 , 79 , 79 ] ,
"darkturquoise" : [ 0 , 206 , 209 ] ,
"darkviolet" : [ 148 , 0 , 211 ] ,
"deeppink" : [ 255 , 20 , 147 ] ,
"deepskyblue" : [ 0 , 191 , 255 ] ,
"dimgray" : [ 105 , 105 , 105 ] ,
"dimgrey" : [ 105 , 105 , 105 ] ,
"dodgerblue" : [ 30 , 144 , 255 ] ,
"firebrick" : [ 178 , 34 , 34 ] ,
"floralwhite" : [ 255 , 250 , 240 ] ,
"forestgreen" : [ 34 , 139 , 34 ] ,
"fuchsia" : [ 255 , 0 , 255 ] ,
"gainsboro" : [ 220 , 220 , 220 ] ,
"ghostwhite" : [ 248 , 248 , 255 ] ,
"gold" : [ 255 , 215 , 0 ] ,
"goldenrod" : [ 218 , 165 , 32 ] ,
"gray" : [ 128 , 128 , 128 ] ,
"green" : [ 0 , 128 , 0 ] ,
"greenyellow" : [ 173 , 255 , 47 ] ,
"grey" : [ 128 , 128 , 128 ] ,
"honeydew" : [ 240 , 255 , 240 ] ,
"hotpink" : [ 255 , 105 , 180 ] ,
"indianred" : [ 205 , 92 , 92 ] ,
"indigo" : [ 75 , 0 , 130 ] ,
"ivory" : [ 255 , 255 , 240 ] ,
"khaki" : [ 240 , 230 , 140 ] ,
"lavender" : [ 230 , 230 , 250 ] ,
"lavenderblush" : [ 255 , 240 , 245 ] ,
"lawngreen" : [ 124 , 252 , 0 ] ,
"lemonchiffon" : [ 255 , 250 , 205 ] ,
"lightblue" : [ 173 , 216 , 230 ] ,
"lightcoral" : [ 240 , 128 , 128 ] ,
"lightcyan" : [ 224 , 255 , 255 ] ,
"lightgoldenrodyellow" : [ 250 , 250 , 210 ] ,
"lightgray" : [ 211 , 211 , 211 ] ,
"lightgreen" : [ 144 , 238 , 144 ] ,
"lightgrey" : [ 211 , 211 , 211 ] ,
"lightpink" : [ 255 , 182 , 193 ] ,
"lightsalmon" : [ 255 , 160 , 122 ] ,
"lightseagreen" : [ 32 , 178 , 170 ] ,
"lightskyblue" : [ 135 , 206 , 250 ] ,
"lightslategray" : [ 119 , 136 , 153 ] ,
"lightslategrey" : [ 119 , 136 , 153 ] ,
"lightsteelblue" : [ 176 , 196 , 222 ] ,
"lightyellow" : [ 255 , 255 , 224 ] ,
"lime" : [ 0 , 255 , 0 ] ,
"limegreen" : [ 50 , 205 , 50 ] ,
"linen" : [ 250 , 240 , 230 ] ,
"magenta" : [ 255 , 0 , 255 ] ,
"maroon" : [ 128 , 0 , 0 ] ,
"mediumaquamarine" : [ 102 , 205 , 170 ] ,
"mediumblue" : [ 0 , 0 , 205 ] ,
"mediumorchid" : [ 186 , 85 , 211 ] ,
"mediumpurple" : [ 147 , 112 , 219 ] ,
"mediumseagreen" : [ 60 , 179 , 113 ] ,
"mediumslateblue" : [ 123 , 104 , 238 ] ,
"mediumspringgreen" : [ 0 , 250 , 154 ] ,
"mediumturquoise" : [ 72 , 209 , 204 ] ,
"mediumvioletred" : [ 199 , 21 , 133 ] ,
"midnightblue" : [ 25 , 25 , 112 ] ,
"mintcream" : [ 245 , 255 , 250 ] ,
"mistyrose" : [ 255 , 228 , 225 ] ,
"moccasin" : [ 255 , 228 , 181 ] ,
"navajowhite" : [ 255 , 222 , 173 ] ,
"navy" : [ 0 , 0 , 128 ] ,
"oldlace" : [ 253 , 245 , 230 ] ,
"olive" : [ 128 , 128 , 0 ] ,
"olivedrab" : [ 107 , 142 , 35 ] ,
"orange" : [ 255 , 165 , 0 ] ,
"orangered" : [ 255 , 69 , 0 ] ,
"orchid" : [ 218 , 112 , 214 ] ,
"palegoldenrod" : [ 238 , 232 , 170 ] ,
"palegreen" : [ 152 , 251 , 152 ] ,
"paleturquoise" : [ 175 , 238 , 238 ] ,
"palevioletred" : [ 219 , 112 , 147 ] ,
"papayawhip" : [ 255 , 239 , 213 ] ,
"peachpuff" : [ 255 , 218 , 185 ] ,
"peru" : [ 205 , 133 , 63 ] ,
"pink" : [ 255 , 192 , 203 ] ,
"plum" : [ 221 , 160 , 221 ] ,
"powderblue" : [ 176 , 224 , 230 ] ,
"purple" : [ 128 , 0 , 128 ] ,
"rebeccapurple" : [ 102 , 51 , 153 ] ,
"red" : [ 255 , 0 , 0 ] ,
"rosybrown" : [ 188 , 143 , 143 ] ,
"royalblue" : [ 65 , 105 , 225 ] ,
"saddlebrown" : [ 139 , 69 , 19 ] ,
"salmon" : [ 250 , 128 , 114 ] ,
"sandybrown" : [ 244 , 164 , 96 ] ,
"seagreen" : [ 46 , 139 , 87 ] ,
"seashell" : [ 255 , 245 , 238 ] ,
"sienna" : [ 160 , 82 , 45 ] ,
"silver" : [ 192 , 192 , 192 ] ,
"skyblue" : [ 135 , 206 , 235 ] ,
"slateblue" : [ 106 , 90 , 205 ] ,
"slategray" : [ 112 , 128 , 144 ] ,
"slategrey" : [ 112 , 128 , 144 ] ,
"snow" : [ 255 , 250 , 250 ] ,
"springgreen" : [ 0 , 255 , 127 ] ,
"steelblue" : [ 70 , 130 , 180 ] ,
"tan" : [ 210 , 180 , 140 ] ,
"teal" : [ 0 , 128 , 128 ] ,
"thistle" : [ 216 , 191 , 216 ] ,
"tomato" : [ 255 , 99 , 71 ] ,
"turquoise" : [ 64 , 224 , 208 ] ,
"violet" : [ 238 , 130 , 238 ] ,
"wheat" : [ 245 , 222 , 179 ] ,
"white" : [ 255 , 255 , 255 ] ,
"whitesmoke" : [ 245 , 245 , 245 ] ,
"yellow" : [ 255 , 255 , 0 ] ,
"yellowgreen" : [ 154 , 205 , 50 ]
} ;
} , { } ] , 6 : [ function ( require , module , exports ) {
//! moment.js
//! version : 2.13.0
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com
; ( function ( global , factory ) {
typeof exports === 'object' && typeof module !== 'undefined' ? module . exports = factory ( ) :
typeof define === 'function' && define . amd ? define ( factory ) :
global . moment = factory ( )
} ( this , function ( ) { 'use strict' ;
var hookCallback ;
function utils _hooks _ _hooks ( ) {
return hookCallback . apply ( null , arguments ) ;
}
// This is done to register the method called with moment()
// without creating circular dependencies.
function setHookCallback ( callback ) {
hookCallback = callback ;
}
function isArray ( input ) {
return input instanceof Array || Object . prototype . toString . call ( input ) === '[object Array]' ;
}
function isDate ( input ) {
return input instanceof Date || Object . prototype . toString . call ( input ) === '[object Date]' ;
}
function map ( arr , fn ) {
var res = [ ] , i ;
for ( i = 0 ; i < arr . length ; ++ i ) {
res . push ( fn ( arr [ i ] , i ) ) ;
}
return res ;
}
function hasOwnProp ( a , b ) {
return Object . prototype . hasOwnProperty . call ( a , b ) ;
}
function extend ( a , b ) {
for ( var i in b ) {
if ( hasOwnProp ( b , i ) ) {
a [ i ] = b [ i ] ;
}
}
if ( hasOwnProp ( b , 'toString' ) ) {
a . toString = b . toString ;
}
if ( hasOwnProp ( b , 'valueOf' ) ) {
a . valueOf = b . valueOf ;
}
return a ;
}
function create _utc _ _createUTC ( input , format , locale , strict ) {
return createLocalOrUTC ( input , format , locale , strict , true ) . utc ( ) ;
}
function defaultParsingFlags ( ) {
// We need to deep clone this object.
return {
empty : false ,
unusedTokens : [ ] ,
unusedInput : [ ] ,
overflow : - 2 ,
charsLeftOver : 0 ,
nullInput : false ,
invalidMonth : null ,
invalidFormat : false ,
userInvalidated : false ,
iso : false ,
parsedDateParts : [ ] ,
meridiem : null
} ;
}
function getParsingFlags ( m ) {
if ( m . _pf == null ) {
m . _pf = defaultParsingFlags ( ) ;
}
return m . _pf ;
}
var some ;
if ( Array . prototype . some ) {
some = Array . prototype . some ;
} else {
some = function ( fun ) {
var t = Object ( this ) ;
var len = t . length >>> 0 ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( i in t && fun . call ( this , t [ i ] , i , t ) ) {
return true ;
}
}
return false ;
} ;
}
function valid _ _isValid ( m ) {
if ( m . _isValid == null ) {
var flags = getParsingFlags ( m ) ;
var parsedParts = some . call ( flags . parsedDateParts , function ( i ) {
return i != null ;
} ) ;
m . _isValid = ! isNaN ( m . _d . getTime ( ) ) &&
flags . overflow < 0 &&
! flags . empty &&
! flags . invalidMonth &&
! flags . invalidWeekday &&
! flags . nullInput &&
! flags . invalidFormat &&
! flags . userInvalidated &&
( ! flags . meridiem || ( flags . meridiem && parsedParts ) ) ;
if ( m . _strict ) {
m . _isValid = m . _isValid &&
flags . charsLeftOver === 0 &&
flags . unusedTokens . length === 0 &&
flags . bigHour === undefined ;
}
}
return m . _isValid ;
}
function valid _ _createInvalid ( flags ) {
var m = create _utc _ _createUTC ( NaN ) ;
if ( flags != null ) {
extend ( getParsingFlags ( m ) , flags ) ;
}
else {
getParsingFlags ( m ) . userInvalidated = true ;
}
return m ;
}
function isUndefined ( input ) {
return input === void 0 ;
}
// Plugins that add properties should also add the key here (null value),
// so we can properly clone ourselves.
var momentProperties = utils _hooks _ _hooks . momentProperties = [ ] ;
function copyConfig ( to , from ) {
var i , prop , val ;
if ( ! isUndefined ( from . _isAMomentObject ) ) {
to . _isAMomentObject = from . _isAMomentObject ;
}
if ( ! isUndefined ( from . _i ) ) {
to . _i = from . _i ;
}
if ( ! isUndefined ( from . _f ) ) {
to . _f = from . _f ;
}
if ( ! isUndefined ( from . _l ) ) {
to . _l = from . _l ;
}
if ( ! isUndefined ( from . _strict ) ) {
to . _strict = from . _strict ;
}
if ( ! isUndefined ( from . _tzm ) ) {
to . _tzm = from . _tzm ;
}
if ( ! isUndefined ( from . _isUTC ) ) {
to . _isUTC = from . _isUTC ;
}
if ( ! isUndefined ( from . _offset ) ) {
to . _offset = from . _offset ;
}
if ( ! isUndefined ( from . _pf ) ) {
to . _pf = getParsingFlags ( from ) ;
}
if ( ! isUndefined ( from . _locale ) ) {
to . _locale = from . _locale ;
}
if ( momentProperties . length > 0 ) {
for ( i in momentProperties ) {
prop = momentProperties [ i ] ;
val = from [ prop ] ;
if ( ! isUndefined ( val ) ) {
to [ prop ] = val ;
}
}
}
return to ;
}
var updateInProgress = false ;
// Moment prototype object
function Moment ( config ) {
copyConfig ( this , config ) ;
this . _d = new Date ( config . _d != null ? config . _d . getTime ( ) : NaN ) ;
// Prevent infinite loop in case updateOffset creates new moment
// objects.
if ( updateInProgress === false ) {
updateInProgress = true ;
utils _hooks _ _hooks . updateOffset ( this ) ;
updateInProgress = false ;
}
}
function isMoment ( obj ) {
return obj instanceof Moment || ( obj != null && obj . _isAMomentObject != null ) ;
}
function absFloor ( number ) {
if ( number < 0 ) {
return Math . ceil ( number ) ;
} else {
return Math . floor ( number ) ;
}
}
function toInt ( argumentForCoercion ) {
var coercedNumber = + argumentForCoercion ,
value = 0 ;
if ( coercedNumber !== 0 && isFinite ( coercedNumber ) ) {
value = absFloor ( coercedNumber ) ;
}
return value ;
}
// compare two arrays, return the number of differences
function compareArrays ( array1 , array2 , dontConvert ) {
var len = Math . min ( array1 . length , array2 . length ) ,
lengthDiff = Math . abs ( array1 . length - array2 . length ) ,
diffs = 0 ,
i ;
for ( i = 0 ; i < len ; i ++ ) {
if ( ( dontConvert && array1 [ i ] !== array2 [ i ] ) ||
( ! dontConvert && toInt ( array1 [ i ] ) !== toInt ( array2 [ i ] ) ) ) {
diffs ++ ;
}
}
return diffs + lengthDiff ;
}
function warn ( msg ) {
if ( utils _hooks _ _hooks . suppressDeprecationWarnings === false &&
( typeof console !== 'undefined' ) && console . warn ) {
console . warn ( 'Deprecation warning: ' + msg ) ;
}
}
function deprecate ( msg , fn ) {
var firstTime = true ;
return extend ( function ( ) {
if ( utils _hooks _ _hooks . deprecationHandler != null ) {
utils _hooks _ _hooks . deprecationHandler ( null , msg ) ;
}
if ( firstTime ) {
warn ( msg + '\nArguments: ' + Array . prototype . slice . call ( arguments ) . join ( ', ' ) + '\n' + ( new Error ( ) ) . stack ) ;
firstTime = false ;
}
return fn . apply ( this , arguments ) ;
} , fn ) ;
}
var deprecations = { } ;
function deprecateSimple ( name , msg ) {
if ( utils _hooks _ _hooks . deprecationHandler != null ) {
utils _hooks _ _hooks . deprecationHandler ( name , msg ) ;
}
if ( ! deprecations [ name ] ) {
warn ( msg ) ;
deprecations [ name ] = true ;
}
}
utils _hooks _ _hooks . suppressDeprecationWarnings = false ;
utils _hooks _ _hooks . deprecationHandler = null ;
function isFunction ( input ) {
return input instanceof Function || Object . prototype . toString . call ( input ) === '[object Function]' ;
}
function isObject ( input ) {
return Object . prototype . toString . call ( input ) === '[object Object]' ;
}
function locale _set _ _set ( config ) {
var prop , i ;
for ( i in config ) {
prop = config [ i ] ;
if ( isFunction ( prop ) ) {
this [ i ] = prop ;
} else {
this [ '_' + i ] = prop ;
}
}
this . _config = config ;
// Lenient ordinal parsing accepts just a number in addition to
// number + (possibly) stuff coming from _ordinalParseLenient.
this . _ordinalParseLenient = new RegExp ( this . _ordinalParse . source + '|' + ( /\d{1,2}/ ) . source ) ;
}
function mergeConfigs ( parentConfig , childConfig ) {
var res = extend ( { } , parentConfig ) , prop ;
for ( prop in childConfig ) {
if ( hasOwnProp ( childConfig , prop ) ) {
if ( isObject ( parentConfig [ prop ] ) && isObject ( childConfig [ prop ] ) ) {
res [ prop ] = { } ;
extend ( res [ prop ] , parentConfig [ prop ] ) ;
extend ( res [ prop ] , childConfig [ prop ] ) ;
} else if ( childConfig [ prop ] != null ) {
res [ prop ] = childConfig [ prop ] ;
} else {
delete res [ prop ] ;
}
}
}
return res ;
}
function Locale ( config ) {
if ( config != null ) {
this . set ( config ) ;
}
}
var keys ;
if ( Object . keys ) {
keys = Object . keys ;
} else {
keys = function ( obj ) {
var i , res = [ ] ;
for ( i in obj ) {
if ( hasOwnProp ( obj , i ) ) {
res . push ( i ) ;
}
}
return res ;
} ;
}
// internal storage for locale config files
var locales = { } ;
var globalLocale ;
function normalizeLocale ( key ) {
return key ? key . toLowerCase ( ) . replace ( '_' , '-' ) : key ;
}
// pick the locale from the array
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
function chooseLocale ( names ) {
var i = 0 , j , next , locale , split ;
while ( i < names . length ) {
split = normalizeLocale ( names [ i ] ) . split ( '-' ) ;
j = split . length ;
next = normalizeLocale ( names [ i + 1 ] ) ;
next = next ? next . split ( '-' ) : null ;
while ( j > 0 ) {
locale = loadLocale ( split . slice ( 0 , j ) . join ( '-' ) ) ;
if ( locale ) {
return locale ;
}
if ( next && next . length >= j && compareArrays ( split , next , true ) >= j - 1 ) {
//the next array item is better than a shallower substring of this one
break ;
}
j -- ;
}
i ++ ;
}
return null ;
}
function loadLocale ( name ) {
var oldLocale = null ;
// TODO: Find a better way to register and load all the locales in Node
if ( ! locales [ name ] && ( typeof module !== 'undefined' ) &&
module && module . exports ) {
try {
oldLocale = globalLocale . _abbr ;
require ( './locale/' + name ) ;
// because defineLocale currently also sets the global locale, we
// want to undo that for lazy loaded locales
locale _locales _ _getSetGlobalLocale ( oldLocale ) ;
} catch ( e ) { }
}
return locales [ name ] ;
}
// This function will load locale and then set the global locale. If
// no arguments are passed in, it will simply return the current global
// locale key.
function locale _locales _ _getSetGlobalLocale ( key , values ) {
var data ;
if ( key ) {
if ( isUndefined ( values ) ) {
data = locale _locales _ _getLocale ( key ) ;
}
else {
data = defineLocale ( key , values ) ;
}
if ( data ) {
// moment.duration._locale = moment._locale = data;
globalLocale = data ;
}
}
return globalLocale . _abbr ;
}
function defineLocale ( name , config ) {
if ( config !== null ) {
config . abbr = name ;
if ( locales [ name ] != null ) {
deprecateSimple ( 'defineLocaleOverride' ,
'use moment.updateLocale(localeName, config) to change ' +
'an existing locale. moment.defineLocale(localeName, ' +
'config) should only be used for creating a new locale' ) ;
config = mergeConfigs ( locales [ name ] . _config , config ) ;
} else if ( config . parentLocale != null ) {
if ( locales [ config . parentLocale ] != null ) {
config = mergeConfigs ( locales [ config . parentLocale ] . _config , config ) ;
} else {
// treat as if there is no base config
deprecateSimple ( 'parentLocaleUndefined' ,
'specified parentLocale is not defined yet' ) ;
}
}
locales [ name ] = new Locale ( config ) ;
// backwards compat for now: also set the locale
locale _locales _ _getSetGlobalLocale ( name ) ;
return locales [ name ] ;
} else {
// useful for testing
delete locales [ name ] ;
return null ;
}
}
function updateLocale ( name , config ) {
if ( config != null ) {
var locale ;
if ( locales [ name ] != null ) {
config = mergeConfigs ( locales [ name ] . _config , config ) ;
}
locale = new Locale ( config ) ;
locale . parentLocale = locales [ name ] ;
locales [ name ] = locale ;
// backwards compat for now: also set the locale
locale _locales _ _getSetGlobalLocale ( name ) ;
} else {
// pass null for config to unupdate, useful for tests
if ( locales [ name ] != null ) {
if ( locales [ name ] . parentLocale != null ) {
locales [ name ] = locales [ name ] . parentLocale ;
} else if ( locales [ name ] != null ) {
delete locales [ name ] ;
}
}
}
return locales [ name ] ;
}
// returns locale data
function locale _locales _ _getLocale ( key ) {
var locale ;
if ( key && key . _locale && key . _locale . _abbr ) {
key = key . _locale . _abbr ;
}
if ( ! key ) {
return globalLocale ;
}
if ( ! isArray ( key ) ) {
//short-circuit everything else
locale = loadLocale ( key ) ;
if ( locale ) {
return locale ;
}
key = [ key ] ;
}
return chooseLocale ( key ) ;
}
function locale _locales _ _listLocales ( ) {
return keys ( locales ) ;
}
var aliases = { } ;
function addUnitAlias ( unit , shorthand ) {
var lowerCase = unit . toLowerCase ( ) ;
aliases [ lowerCase ] = aliases [ lowerCase + 's' ] = aliases [ shorthand ] = unit ;
}
function normalizeUnits ( units ) {
return typeof units === 'string' ? aliases [ units ] || aliases [ units . toLowerCase ( ) ] : undefined ;
}
function normalizeObjectUnits ( inputObject ) {
var normalizedInput = { } ,
normalizedProp ,
prop ;
for ( prop in inputObject ) {
if ( hasOwnProp ( inputObject , prop ) ) {
normalizedProp = normalizeUnits ( prop ) ;
if ( normalizedProp ) {
normalizedInput [ normalizedProp ] = inputObject [ prop ] ;
}
}
}
return normalizedInput ;
}
function makeGetSet ( unit , keepTime ) {
return function ( value ) {
if ( value != null ) {
get _set _ _set ( this , unit , value ) ;
utils _hooks _ _hooks . updateOffset ( this , keepTime ) ;
return this ;
} else {
return get _set _ _get ( this , unit ) ;
}
} ;
}
function get _set _ _get ( mom , unit ) {
return mom . isValid ( ) ?
mom . _d [ 'get' + ( mom . _isUTC ? 'UTC' : '' ) + unit ] ( ) : NaN ;
}
function get _set _ _set ( mom , unit , value ) {
if ( mom . isValid ( ) ) {
mom . _d [ 'set' + ( mom . _isUTC ? 'UTC' : '' ) + unit ] ( value ) ;
}
}
// MOMENTS
function getSet ( units , value ) {
var unit ;
if ( typeof units === 'object' ) {
for ( unit in units ) {
this . set ( unit , units [ unit ] ) ;
}
} else {
units = normalizeUnits ( units ) ;
if ( isFunction ( this [ units ] ) ) {
return this [ units ] ( value ) ;
}
}
return this ;
}
function zeroFill ( number , targetLength , forceSign ) {
var absNumber = '' + Math . abs ( number ) ,
zerosToFill = targetLength - absNumber . length ,
sign = number >= 0 ;
return ( sign ? ( forceSign ? '+' : '' ) : '-' ) +
Math . pow ( 10 , Math . max ( 0 , zerosToFill ) ) . toString ( ) . substr ( 1 ) + absNumber ;
}
var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g ;
var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g ;
var formatFunctions = { } ;
var formatTokenFunctions = { } ;
// token: 'M'
// padded: ['MM', 2]
// ordinal: 'Mo'
// callback: function () { this.month() + 1 }
function addFormatToken ( token , padded , ordinal , callback ) {
var func = callback ;
if ( typeof callback === 'string' ) {
func = function ( ) {
return this [ callback ] ( ) ;
} ;
}
if ( token ) {
formatTokenFunctions [ token ] = func ;
}
if ( padded ) {
formatTokenFunctions [ padded [ 0 ] ] = function ( ) {
return zeroFill ( func . apply ( this , arguments ) , padded [ 1 ] , padded [ 2 ] ) ;
} ;
}
if ( ordinal ) {
formatTokenFunctions [ ordinal ] = function ( ) {
return this . localeData ( ) . ordinal ( func . apply ( this , arguments ) , token ) ;
} ;
}
}
function removeFormattingTokens ( input ) {
if ( input . match ( /\[[\s\S]/ ) ) {
return input . replace ( /^\[|\]$/g , '' ) ;
}
return input . replace ( /\\/g , '' ) ;
}
function makeFormatFunction ( format ) {
var array = format . match ( formattingTokens ) , i , length ;
for ( i = 0 , length = array . length ; i < length ; i ++ ) {
if ( formatTokenFunctions [ array [ i ] ] ) {
array [ i ] = formatTokenFunctions [ array [ i ] ] ;
} else {
array [ i ] = removeFormattingTokens ( array [ i ] ) ;
}
}
return function ( mom ) {
var output = '' , i ;
for ( i = 0 ; i < length ; i ++ ) {
output += array [ i ] instanceof Function ? array [ i ] . call ( mom , format ) : array [ i ] ;
}
return output ;
} ;
}
// format date using native date object
function formatMoment ( m , format ) {
if ( ! m . isValid ( ) ) {
return m . localeData ( ) . invalidDate ( ) ;
}
format = expandFormat ( format , m . localeData ( ) ) ;
formatFunctions [ format ] = formatFunctions [ format ] || makeFormatFunction ( format ) ;
return formatFunctions [ format ] ( m ) ;
}
function expandFormat ( format , locale ) {
var i = 5 ;
function replaceLongDateFormatTokens ( input ) {
return locale . longDateFormat ( input ) || input ;
}
localFormattingTokens . lastIndex = 0 ;
while ( i >= 0 && localFormattingTokens . test ( format ) ) {
format = format . replace ( localFormattingTokens , replaceLongDateFormatTokens ) ;
localFormattingTokens . lastIndex = 0 ;
i -= 1 ;
}
return format ;
}
var match1 = /\d/ ; // 0 - 9
var match2 = /\d\d/ ; // 00 - 99
var match3 = /\d{3}/ ; // 000 - 999
var match4 = /\d{4}/ ; // 0000 - 9999
var match6 = /[+-]?\d{6}/ ; // -999999 - 999999
var match1to2 = /\d\d?/ ; // 0 - 99
var match3to4 = /\d\d\d\d?/ ; // 999 - 9999
var match5to6 = /\d\d\d\d\d\d?/ ; // 99999 - 999999
var match1to3 = /\d{1,3}/ ; // 0 - 999
var match1to4 = /\d{1,4}/ ; // 0 - 9999
var match1to6 = /[+-]?\d{1,6}/ ; // -999999 - 999999
var matchUnsigned = /\d+/ ; // 0 - inf
var matchSigned = /[+-]?\d+/ ; // -inf - inf
var matchOffset = /Z|[+-]\d\d:?\d\d/gi ; // +00:00 -00:00 +0000 -0000 or Z
var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi ; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/ ; // 123456789 123456789.123
// any word (or two) characters or numbers including two/three word month in arabic.
// includes scottish gaelic two word and hyphenated months
var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i ;
var regexes = { } ;
function addRegexToken ( token , regex , strictRegex ) {
regexes [ token ] = isFunction ( regex ) ? regex : function ( isStrict , localeData ) {
return ( isStrict && strictRegex ) ? strictRegex : regex ;
} ;
}
function getParseRegexForToken ( token , config ) {
if ( ! hasOwnProp ( regexes , token ) ) {
return new RegExp ( unescapeFormat ( token ) ) ;
}
return regexes [ token ] ( config . _strict , config . _locale ) ;
}
// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
function unescapeFormat ( s ) {
return regexEscape ( s . replace ( '\\' , '' ) . replace ( /\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g , function ( matched , p1 , p2 , p3 , p4 ) {
return p1 || p2 || p3 || p4 ;
} ) ) ;
}
function regexEscape ( s ) {
return s . replace ( /[-\/\\^$*+?.()|[\]{}]/g , '\\$&' ) ;
}
var tokens = { } ;
function addParseToken ( token , callback ) {
var i , func = callback ;
if ( typeof token === 'string' ) {
token = [ token ] ;
}
if ( typeof callback === 'number' ) {
func = function ( input , array ) {
array [ callback ] = toInt ( input ) ;
} ;
}
for ( i = 0 ; i < token . length ; i ++ ) {
tokens [ token [ i ] ] = func ;
}
}
function addWeekParseToken ( token , callback ) {
addParseToken ( token , function ( input , array , config , token ) {
config . _w = config . _w || { } ;
callback ( input , config . _w , config , token ) ;
} ) ;
}
function addTimeToArrayFromToken ( token , input , config ) {
if ( input != null && hasOwnProp ( tokens , token ) ) {
tokens [ token ] ( input , config . _a , config , token ) ;
}
}
var YEAR = 0 ;
var MONTH = 1 ;
var DATE = 2 ;
var HOUR = 3 ;
var MINUTE = 4 ;
var SECOND = 5 ;
var MILLISECOND = 6 ;
var WEEK = 7 ;
var WEEKDAY = 8 ;
var indexOf ;
if ( Array . prototype . indexOf ) {
indexOf = Array . prototype . indexOf ;
} else {
indexOf = function ( o ) {
// I know
var i ;
for ( i = 0 ; i < this . length ; ++ i ) {
if ( this [ i ] === o ) {
return i ;
}
}
return - 1 ;
} ;
}
function daysInMonth ( year , month ) {
return new Date ( Date . UTC ( year , month + 1 , 0 ) ) . getUTCDate ( ) ;
}
// FORMATTING
addFormatToken ( 'M' , [ 'MM' , 2 ] , 'Mo' , function ( ) {
return this . month ( ) + 1 ;
} ) ;
addFormatToken ( 'MMM' , 0 , 0 , function ( format ) {
return this . localeData ( ) . monthsShort ( this , format ) ;
} ) ;
addFormatToken ( 'MMMM' , 0 , 0 , function ( format ) {
return this . localeData ( ) . months ( this , format ) ;
} ) ;
// ALIASES
addUnitAlias ( 'month' , 'M' ) ;
// PARSING
addRegexToken ( 'M' , match1to2 ) ;
addRegexToken ( 'MM' , match1to2 , match2 ) ;
addRegexToken ( 'MMM' , function ( isStrict , locale ) {
return locale . monthsShortRegex ( isStrict ) ;
} ) ;
addRegexToken ( 'MMMM' , function ( isStrict , locale ) {
return locale . monthsRegex ( isStrict ) ;
} ) ;
addParseToken ( [ 'M' , 'MM' ] , function ( input , array ) {
array [ MONTH ] = toInt ( input ) - 1 ;
} ) ;
addParseToken ( [ 'MMM' , 'MMMM' ] , function ( input , array , config , token ) {
var month = config . _locale . monthsParse ( input , token , config . _strict ) ;
// if we didn't find a month name, mark the date as invalid.
if ( month != null ) {
array [ MONTH ] = month ;
} else {
getParsingFlags ( config ) . invalidMonth = input ;
}
} ) ;
// LOCALES
2022-03-17 04:10:44 -07:00
var MONTHS _IN _FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/ ;
2016-05-24 16:09:28 -07:00
var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December' . split ( '_' ) ;
function localeMonths ( m , format ) {
return isArray ( this . _months ) ? this . _months [ m . month ( ) ] :
this . _months [ MONTHS _IN _FORMAT . test ( format ) ? 'format' : 'standalone' ] [ m . month ( ) ] ;
}
var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec' . split ( '_' ) ;
function localeMonthsShort ( m , format ) {
return isArray ( this . _monthsShort ) ? this . _monthsShort [ m . month ( ) ] :
this . _monthsShort [ MONTHS _IN _FORMAT . test ( format ) ? 'format' : 'standalone' ] [ m . month ( ) ] ;
}
function units _month _ _handleStrictParse ( monthName , format , strict ) {
var i , ii , mom , llc = monthName . toLocaleLowerCase ( ) ;
if ( ! this . _monthsParse ) {
// this is not used
this . _monthsParse = [ ] ;
this . _longMonthsParse = [ ] ;
this . _shortMonthsParse = [ ] ;
for ( i = 0 ; i < 12 ; ++ i ) {
mom = create _utc _ _createUTC ( [ 2000 , i ] ) ;
this . _shortMonthsParse [ i ] = this . monthsShort ( mom , '' ) . toLocaleLowerCase ( ) ;
this . _longMonthsParse [ i ] = this . months ( mom , '' ) . toLocaleLowerCase ( ) ;
}
}
if ( strict ) {
if ( format === 'MMM' ) {
ii = indexOf . call ( this . _shortMonthsParse , llc ) ;
return ii !== - 1 ? ii : null ;
} else {
ii = indexOf . call ( this . _longMonthsParse , llc ) ;
return ii !== - 1 ? ii : null ;
}
} else {
if ( format === 'MMM' ) {
ii = indexOf . call ( this . _shortMonthsParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _longMonthsParse , llc ) ;
return ii !== - 1 ? ii : null ;
} else {
ii = indexOf . call ( this . _longMonthsParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _shortMonthsParse , llc ) ;
return ii !== - 1 ? ii : null ;
}
}
}
function localeMonthsParse ( monthName , format , strict ) {
var i , mom , regex ;
if ( this . _monthsParseExact ) {
return units _month _ _handleStrictParse . call ( this , monthName , format , strict ) ;
}
if ( ! this . _monthsParse ) {
this . _monthsParse = [ ] ;
this . _longMonthsParse = [ ] ;
this . _shortMonthsParse = [ ] ;
}
// TODO: add sorting
// Sorting makes sure if one month (or abbr) is a prefix of another
// see sorting in computeMonthsParse
for ( i = 0 ; i < 12 ; i ++ ) {
// make the regex if we don't have it already
mom = create _utc _ _createUTC ( [ 2000 , i ] ) ;
if ( strict && ! this . _longMonthsParse [ i ] ) {
this . _longMonthsParse [ i ] = new RegExp ( '^' + this . months ( mom , '' ) . replace ( '.' , '' ) + '$' , 'i' ) ;
this . _shortMonthsParse [ i ] = new RegExp ( '^' + this . monthsShort ( mom , '' ) . replace ( '.' , '' ) + '$' , 'i' ) ;
}
if ( ! strict && ! this . _monthsParse [ i ] ) {
regex = '^' + this . months ( mom , '' ) + '|^' + this . monthsShort ( mom , '' ) ;
this . _monthsParse [ i ] = new RegExp ( regex . replace ( '.' , '' ) , 'i' ) ;
}
// test the regex
if ( strict && format === 'MMMM' && this . _longMonthsParse [ i ] . test ( monthName ) ) {
return i ;
} else if ( strict && format === 'MMM' && this . _shortMonthsParse [ i ] . test ( monthName ) ) {
return i ;
} else if ( ! strict && this . _monthsParse [ i ] . test ( monthName ) ) {
return i ;
}
}
}
// MOMENTS
function setMonth ( mom , value ) {
var dayOfMonth ;
if ( ! mom . isValid ( ) ) {
// No op
return mom ;
}
if ( typeof value === 'string' ) {
if ( /^\d+$/ . test ( value ) ) {
value = toInt ( value ) ;
} else {
value = mom . localeData ( ) . monthsParse ( value ) ;
// TODO: Another silent failure?
if ( typeof value !== 'number' ) {
return mom ;
}
}
}
dayOfMonth = Math . min ( mom . date ( ) , daysInMonth ( mom . year ( ) , value ) ) ;
mom . _d [ 'set' + ( mom . _isUTC ? 'UTC' : '' ) + 'Month' ] ( value , dayOfMonth ) ;
return mom ;
}
function getSetMonth ( value ) {
if ( value != null ) {
setMonth ( this , value ) ;
utils _hooks _ _hooks . updateOffset ( this , true ) ;
return this ;
} else {
return get _set _ _get ( this , 'Month' ) ;
}
}
function getDaysInMonth ( ) {
return daysInMonth ( this . year ( ) , this . month ( ) ) ;
}
var defaultMonthsShortRegex = matchWord ;
function monthsShortRegex ( isStrict ) {
if ( this . _monthsParseExact ) {
if ( ! hasOwnProp ( this , '_monthsRegex' ) ) {
computeMonthsParse . call ( this ) ;
}
if ( isStrict ) {
return this . _monthsShortStrictRegex ;
} else {
return this . _monthsShortRegex ;
}
} else {
return this . _monthsShortStrictRegex && isStrict ?
this . _monthsShortStrictRegex : this . _monthsShortRegex ;
}
}
var defaultMonthsRegex = matchWord ;
function monthsRegex ( isStrict ) {
if ( this . _monthsParseExact ) {
if ( ! hasOwnProp ( this , '_monthsRegex' ) ) {
computeMonthsParse . call ( this ) ;
}
if ( isStrict ) {
return this . _monthsStrictRegex ;
} else {
return this . _monthsRegex ;
}
} else {
return this . _monthsStrictRegex && isStrict ?
this . _monthsStrictRegex : this . _monthsRegex ;
}
}
function computeMonthsParse ( ) {
function cmpLenRev ( a , b ) {
return b . length - a . length ;
}
var shortPieces = [ ] , longPieces = [ ] , mixedPieces = [ ] ,
i , mom ;
for ( i = 0 ; i < 12 ; i ++ ) {
// make the regex if we don't have it already
mom = create _utc _ _createUTC ( [ 2000 , i ] ) ;
shortPieces . push ( this . monthsShort ( mom , '' ) ) ;
longPieces . push ( this . months ( mom , '' ) ) ;
mixedPieces . push ( this . months ( mom , '' ) ) ;
mixedPieces . push ( this . monthsShort ( mom , '' ) ) ;
}
// Sorting makes sure if one month (or abbr) is a prefix of another it
// will match the longer piece.
shortPieces . sort ( cmpLenRev ) ;
longPieces . sort ( cmpLenRev ) ;
mixedPieces . sort ( cmpLenRev ) ;
for ( i = 0 ; i < 12 ; i ++ ) {
shortPieces [ i ] = regexEscape ( shortPieces [ i ] ) ;
longPieces [ i ] = regexEscape ( longPieces [ i ] ) ;
mixedPieces [ i ] = regexEscape ( mixedPieces [ i ] ) ;
}
this . _monthsRegex = new RegExp ( '^(' + mixedPieces . join ( '|' ) + ')' , 'i' ) ;
this . _monthsShortRegex = this . _monthsRegex ;
this . _monthsStrictRegex = new RegExp ( '^(' + longPieces . join ( '|' ) + ')' , 'i' ) ;
this . _monthsShortStrictRegex = new RegExp ( '^(' + shortPieces . join ( '|' ) + ')' , 'i' ) ;
}
function checkOverflow ( m ) {
var overflow ;
var a = m . _a ;
if ( a && getParsingFlags ( m ) . overflow === - 2 ) {
overflow =
a [ MONTH ] < 0 || a [ MONTH ] > 11 ? MONTH :
a [ DATE ] < 1 || a [ DATE ] > daysInMonth ( a [ YEAR ] , a [ MONTH ] ) ? DATE :
a [ HOUR ] < 0 || a [ HOUR ] > 24 || ( a [ HOUR ] === 24 && ( a [ MINUTE ] !== 0 || a [ SECOND ] !== 0 || a [ MILLISECOND ] !== 0 ) ) ? HOUR :
a [ MINUTE ] < 0 || a [ MINUTE ] > 59 ? MINUTE :
a [ SECOND ] < 0 || a [ SECOND ] > 59 ? SECOND :
a [ MILLISECOND ] < 0 || a [ MILLISECOND ] > 999 ? MILLISECOND :
- 1 ;
if ( getParsingFlags ( m ) . _overflowDayOfYear && ( overflow < YEAR || overflow > DATE ) ) {
overflow = DATE ;
}
if ( getParsingFlags ( m ) . _overflowWeeks && overflow === - 1 ) {
overflow = WEEK ;
}
if ( getParsingFlags ( m ) . _overflowWeekday && overflow === - 1 ) {
overflow = WEEKDAY ;
}
getParsingFlags ( m ) . overflow = overflow ;
}
return m ;
}
// iso 8601 regex
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/ ;
var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/ ;
var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/ ;
var isoDates = [
[ 'YYYYYY-MM-DD' , /[+-]\d{6}-\d\d-\d\d/ ] ,
[ 'YYYY-MM-DD' , /\d{4}-\d\d-\d\d/ ] ,
[ 'GGGG-[W]WW-E' , /\d{4}-W\d\d-\d/ ] ,
[ 'GGGG-[W]WW' , /\d{4}-W\d\d/ , false ] ,
[ 'YYYY-DDD' , /\d{4}-\d{3}/ ] ,
[ 'YYYY-MM' , /\d{4}-\d\d/ , false ] ,
[ 'YYYYYYMMDD' , /[+-]\d{10}/ ] ,
[ 'YYYYMMDD' , /\d{8}/ ] ,
// YYYYMM is NOT allowed by the standard
[ 'GGGG[W]WWE' , /\d{4}W\d{3}/ ] ,
[ 'GGGG[W]WW' , /\d{4}W\d{2}/ , false ] ,
[ 'YYYYDDD' , /\d{7}/ ]
] ;
// iso time formats and regexes
var isoTimes = [
[ 'HH:mm:ss.SSSS' , /\d\d:\d\d:\d\d\.\d+/ ] ,
[ 'HH:mm:ss,SSSS' , /\d\d:\d\d:\d\d,\d+/ ] ,
[ 'HH:mm:ss' , /\d\d:\d\d:\d\d/ ] ,
[ 'HH:mm' , /\d\d:\d\d/ ] ,
[ 'HHmmss.SSSS' , /\d\d\d\d\d\d\.\d+/ ] ,
[ 'HHmmss,SSSS' , /\d\d\d\d\d\d,\d+/ ] ,
[ 'HHmmss' , /\d\d\d\d\d\d/ ] ,
[ 'HHmm' , /\d\d\d\d/ ] ,
[ 'HH' , /\d\d/ ]
] ;
var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i ;
// date from iso format
function configFromISO ( config ) {
var i , l ,
string = config . _i ,
match = extendedIsoRegex . exec ( string ) || basicIsoRegex . exec ( string ) ,
allowTime , dateFormat , timeFormat , tzFormat ;
if ( match ) {
getParsingFlags ( config ) . iso = true ;
for ( i = 0 , l = isoDates . length ; i < l ; i ++ ) {
if ( isoDates [ i ] [ 1 ] . exec ( match [ 1 ] ) ) {
dateFormat = isoDates [ i ] [ 0 ] ;
allowTime = isoDates [ i ] [ 2 ] !== false ;
break ;
}
}
if ( dateFormat == null ) {
config . _isValid = false ;
return ;
}
if ( match [ 3 ] ) {
for ( i = 0 , l = isoTimes . length ; i < l ; i ++ ) {
if ( isoTimes [ i ] [ 1 ] . exec ( match [ 3 ] ) ) {
// match[2] should be 'T' or space
timeFormat = ( match [ 2 ] || ' ' ) + isoTimes [ i ] [ 0 ] ;
break ;
}
}
if ( timeFormat == null ) {
config . _isValid = false ;
return ;
}
}
if ( ! allowTime && timeFormat != null ) {
config . _isValid = false ;
return ;
}
if ( match [ 4 ] ) {
if ( tzRegex . exec ( match [ 4 ] ) ) {
tzFormat = 'Z' ;
} else {
config . _isValid = false ;
return ;
}
}
config . _f = dateFormat + ( timeFormat || '' ) + ( tzFormat || '' ) ;
configFromStringAndFormat ( config ) ;
} else {
config . _isValid = false ;
}
}
// date from iso format or fallback
function configFromString ( config ) {
var matched = aspNetJsonRegex . exec ( config . _i ) ;
if ( matched !== null ) {
config . _d = new Date ( + matched [ 1 ] ) ;
return ;
}
configFromISO ( config ) ;
if ( config . _isValid === false ) {
delete config . _isValid ;
utils _hooks _ _hooks . createFromInputFallback ( config ) ;
}
}
utils _hooks _ _hooks . createFromInputFallback = deprecate (
'moment construction falls back to js Date. This is ' +
'discouraged and will be removed in upcoming major ' +
'release. Please refer to ' +
'https://github.com/moment/moment/issues/1407 for more info.' ,
function ( config ) {
config . _d = new Date ( config . _i + ( config . _useUTC ? ' UTC' : '' ) ) ;
}
) ;
function createDate ( y , m , d , h , M , s , ms ) {
//can't just apply() to create a date:
//http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
var date = new Date ( y , m , d , h , M , s , ms ) ;
//the date constructor remaps years 0-99 to 1900-1999
if ( y < 100 && y >= 0 && isFinite ( date . getFullYear ( ) ) ) {
date . setFullYear ( y ) ;
}
return date ;
}
function createUTCDate ( y ) {
var date = new Date ( Date . UTC . apply ( null , arguments ) ) ;
//the Date.UTC function remaps years 0-99 to 1900-1999
if ( y < 100 && y >= 0 && isFinite ( date . getUTCFullYear ( ) ) ) {
date . setUTCFullYear ( y ) ;
}
return date ;
}
// FORMATTING
addFormatToken ( 'Y' , 0 , 0 , function ( ) {
var y = this . year ( ) ;
return y <= 9999 ? '' + y : '+' + y ;
} ) ;
addFormatToken ( 0 , [ 'YY' , 2 ] , 0 , function ( ) {
return this . year ( ) % 100 ;
} ) ;
addFormatToken ( 0 , [ 'YYYY' , 4 ] , 0 , 'year' ) ;
addFormatToken ( 0 , [ 'YYYYY' , 5 ] , 0 , 'year' ) ;
addFormatToken ( 0 , [ 'YYYYYY' , 6 , true ] , 0 , 'year' ) ;
// ALIASES
addUnitAlias ( 'year' , 'y' ) ;
// PARSING
addRegexToken ( 'Y' , matchSigned ) ;
addRegexToken ( 'YY' , match1to2 , match2 ) ;
addRegexToken ( 'YYYY' , match1to4 , match4 ) ;
addRegexToken ( 'YYYYY' , match1to6 , match6 ) ;
addRegexToken ( 'YYYYYY' , match1to6 , match6 ) ;
addParseToken ( [ 'YYYYY' , 'YYYYYY' ] , YEAR ) ;
addParseToken ( 'YYYY' , function ( input , array ) {
array [ YEAR ] = input . length === 2 ? utils _hooks _ _hooks . parseTwoDigitYear ( input ) : toInt ( input ) ;
} ) ;
addParseToken ( 'YY' , function ( input , array ) {
array [ YEAR ] = utils _hooks _ _hooks . parseTwoDigitYear ( input ) ;
} ) ;
addParseToken ( 'Y' , function ( input , array ) {
array [ YEAR ] = parseInt ( input , 10 ) ;
} ) ;
// HELPERS
function daysInYear ( year ) {
return isLeapYear ( year ) ? 366 : 365 ;
}
function isLeapYear ( year ) {
return ( year % 4 === 0 && year % 100 !== 0 ) || year % 400 === 0 ;
}
// HOOKS
utils _hooks _ _hooks . parseTwoDigitYear = function ( input ) {
return toInt ( input ) + ( toInt ( input ) > 68 ? 1900 : 2000 ) ;
} ;
// MOMENTS
var getSetYear = makeGetSet ( 'FullYear' , true ) ;
function getIsLeapYear ( ) {
return isLeapYear ( this . year ( ) ) ;
}
// start-of-first-week - start-of-year
function firstWeekOffset ( year , dow , doy ) {
var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
fwd = 7 + dow - doy ,
// first-week day local weekday -- which local weekday is fwd
fwdlw = ( 7 + createUTCDate ( year , 0 , fwd ) . getUTCDay ( ) - dow ) % 7 ;
return - fwdlw + fwd - 1 ;
}
//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
function dayOfYearFromWeeks ( year , week , weekday , dow , doy ) {
var localWeekday = ( 7 + weekday - dow ) % 7 ,
weekOffset = firstWeekOffset ( year , dow , doy ) ,
dayOfYear = 1 + 7 * ( week - 1 ) + localWeekday + weekOffset ,
resYear , resDayOfYear ;
if ( dayOfYear <= 0 ) {
resYear = year - 1 ;
resDayOfYear = daysInYear ( resYear ) + dayOfYear ;
} else if ( dayOfYear > daysInYear ( year ) ) {
resYear = year + 1 ;
resDayOfYear = dayOfYear - daysInYear ( year ) ;
} else {
resYear = year ;
resDayOfYear = dayOfYear ;
}
return {
year : resYear ,
dayOfYear : resDayOfYear
} ;
}
function weekOfYear ( mom , dow , doy ) {
var weekOffset = firstWeekOffset ( mom . year ( ) , dow , doy ) ,
week = Math . floor ( ( mom . dayOfYear ( ) - weekOffset - 1 ) / 7 ) + 1 ,
resWeek , resYear ;
if ( week < 1 ) {
resYear = mom . year ( ) - 1 ;
resWeek = week + weeksInYear ( resYear , dow , doy ) ;
} else if ( week > weeksInYear ( mom . year ( ) , dow , doy ) ) {
resWeek = week - weeksInYear ( mom . year ( ) , dow , doy ) ;
resYear = mom . year ( ) + 1 ;
} else {
resYear = mom . year ( ) ;
resWeek = week ;
}
return {
week : resWeek ,
year : resYear
} ;
}
function weeksInYear ( year , dow , doy ) {
var weekOffset = firstWeekOffset ( year , dow , doy ) ,
weekOffsetNext = firstWeekOffset ( year + 1 , dow , doy ) ;
return ( daysInYear ( year ) - weekOffset + weekOffsetNext ) / 7 ;
}
// Pick the first defined of two or three arguments.
function defaults ( a , b , c ) {
if ( a != null ) {
return a ;
}
if ( b != null ) {
return b ;
}
return c ;
}
function currentDateArray ( config ) {
// hooks is actually the exported moment object
var nowValue = new Date ( utils _hooks _ _hooks . now ( ) ) ;
if ( config . _useUTC ) {
return [ nowValue . getUTCFullYear ( ) , nowValue . getUTCMonth ( ) , nowValue . getUTCDate ( ) ] ;
}
return [ nowValue . getFullYear ( ) , nowValue . getMonth ( ) , nowValue . getDate ( ) ] ;
}
// convert an array to a date.
// the array should mirror the parameters below
// note: all values past the year are optional and will default to the lowest possible value.
// [year, month, day , hour, minute, second, millisecond]
function configFromArray ( config ) {
var i , date , input = [ ] , currentDate , yearToUse ;
if ( config . _d ) {
return ;
}
currentDate = currentDateArray ( config ) ;
//compute day of the year from weeks and weekdays
if ( config . _w && config . _a [ DATE ] == null && config . _a [ MONTH ] == null ) {
dayOfYearFromWeekInfo ( config ) ;
}
//if the day of the year is set, figure out what it is
if ( config . _dayOfYear ) {
yearToUse = defaults ( config . _a [ YEAR ] , currentDate [ YEAR ] ) ;
if ( config . _dayOfYear > daysInYear ( yearToUse ) ) {
getParsingFlags ( config ) . _overflowDayOfYear = true ;
}
date = createUTCDate ( yearToUse , 0 , config . _dayOfYear ) ;
config . _a [ MONTH ] = date . getUTCMonth ( ) ;
config . _a [ DATE ] = date . getUTCDate ( ) ;
}
// Default to current date.
// * if no year, month, day of month are given, default to today
// * if day of month is given, default month and year
// * if month is given, default only year
// * if year is given, don't default anything
for ( i = 0 ; i < 3 && config . _a [ i ] == null ; ++ i ) {
config . _a [ i ] = input [ i ] = currentDate [ i ] ;
}
// Zero out whatever was not defaulted, including time
for ( ; i < 7 ; i ++ ) {
config . _a [ i ] = input [ i ] = ( config . _a [ i ] == null ) ? ( i === 2 ? 1 : 0 ) : config . _a [ i ] ;
}
// Check for 24:00:00.000
if ( config . _a [ HOUR ] === 24 &&
config . _a [ MINUTE ] === 0 &&
config . _a [ SECOND ] === 0 &&
config . _a [ MILLISECOND ] === 0 ) {
config . _nextDay = true ;
config . _a [ HOUR ] = 0 ;
}
config . _d = ( config . _useUTC ? createUTCDate : createDate ) . apply ( null , input ) ;
// Apply timezone offset from input. The actual utcOffset can be changed
// with parseZone.
if ( config . _tzm != null ) {
config . _d . setUTCMinutes ( config . _d . getUTCMinutes ( ) - config . _tzm ) ;
}
if ( config . _nextDay ) {
config . _a [ HOUR ] = 24 ;
}
}
function dayOfYearFromWeekInfo ( config ) {
var w , weekYear , week , weekday , dow , doy , temp , weekdayOverflow ;
w = config . _w ;
if ( w . GG != null || w . W != null || w . E != null ) {
dow = 1 ;
doy = 4 ;
// TODO: We need to take the current isoWeekYear, but that depends on
// how we interpret now (local, utc, fixed offset). So create
// a now version of current config (take local/utc/offset flags, and
// create now).
weekYear = defaults ( w . GG , config . _a [ YEAR ] , weekOfYear ( local _ _createLocal ( ) , 1 , 4 ) . year ) ;
week = defaults ( w . W , 1 ) ;
weekday = defaults ( w . E , 1 ) ;
if ( weekday < 1 || weekday > 7 ) {
weekdayOverflow = true ;
}
} else {
dow = config . _locale . _week . dow ;
doy = config . _locale . _week . doy ;
weekYear = defaults ( w . gg , config . _a [ YEAR ] , weekOfYear ( local _ _createLocal ( ) , dow , doy ) . year ) ;
week = defaults ( w . w , 1 ) ;
if ( w . d != null ) {
// weekday -- low day numbers are considered next week
weekday = w . d ;
if ( weekday < 0 || weekday > 6 ) {
weekdayOverflow = true ;
}
} else if ( w . e != null ) {
// local weekday -- counting starts from begining of week
weekday = w . e + dow ;
if ( w . e < 0 || w . e > 6 ) {
weekdayOverflow = true ;
}
} else {
// default to begining of week
weekday = dow ;
}
}
if ( week < 1 || week > weeksInYear ( weekYear , dow , doy ) ) {
getParsingFlags ( config ) . _overflowWeeks = true ;
} else if ( weekdayOverflow != null ) {
getParsingFlags ( config ) . _overflowWeekday = true ;
} else {
temp = dayOfYearFromWeeks ( weekYear , week , weekday , dow , doy ) ;
config . _a [ YEAR ] = temp . year ;
config . _dayOfYear = temp . dayOfYear ;
}
}
// constant that refers to the ISO standard
utils _hooks _ _hooks . ISO _8601 = function ( ) { } ;
// date from string and format string
function configFromStringAndFormat ( config ) {
// TODO: Move this to another part of the creation flow to prevent circular deps
if ( config . _f === utils _hooks _ _hooks . ISO _8601 ) {
configFromISO ( config ) ;
return ;
}
config . _a = [ ] ;
getParsingFlags ( config ) . empty = true ;
// This array is used to make a Date, either with `new Date` or `Date.UTC`
var string = '' + config . _i ,
i , parsedInput , tokens , token , skipped ,
stringLength = string . length ,
totalParsedInputLength = 0 ;
tokens = expandFormat ( config . _f , config . _locale ) . match ( formattingTokens ) || [ ] ;
for ( i = 0 ; i < tokens . length ; i ++ ) {
token = tokens [ i ] ;
parsedInput = ( string . match ( getParseRegexForToken ( token , config ) ) || [ ] ) [ 0 ] ;
// console.log('token', token, 'parsedInput', parsedInput,
// 'regex', getParseRegexForToken(token, config));
if ( parsedInput ) {
skipped = string . substr ( 0 , string . indexOf ( parsedInput ) ) ;
if ( skipped . length > 0 ) {
getParsingFlags ( config ) . unusedInput . push ( skipped ) ;
}
string = string . slice ( string . indexOf ( parsedInput ) + parsedInput . length ) ;
totalParsedInputLength += parsedInput . length ;
}
// don't parse if it's not a known token
if ( formatTokenFunctions [ token ] ) {
if ( parsedInput ) {
getParsingFlags ( config ) . empty = false ;
}
else {
getParsingFlags ( config ) . unusedTokens . push ( token ) ;
}
addTimeToArrayFromToken ( token , parsedInput , config ) ;
}
else if ( config . _strict && ! parsedInput ) {
getParsingFlags ( config ) . unusedTokens . push ( token ) ;
}
}
// add remaining unparsed input length to the string
getParsingFlags ( config ) . charsLeftOver = stringLength - totalParsedInputLength ;
if ( string . length > 0 ) {
getParsingFlags ( config ) . unusedInput . push ( string ) ;
}
// clear _12h flag if hour is <= 12
if ( getParsingFlags ( config ) . bigHour === true &&
config . _a [ HOUR ] <= 12 &&
config . _a [ HOUR ] > 0 ) {
getParsingFlags ( config ) . bigHour = undefined ;
}
getParsingFlags ( config ) . parsedDateParts = config . _a . slice ( 0 ) ;
getParsingFlags ( config ) . meridiem = config . _meridiem ;
// handle meridiem
config . _a [ HOUR ] = meridiemFixWrap ( config . _locale , config . _a [ HOUR ] , config . _meridiem ) ;
configFromArray ( config ) ;
checkOverflow ( config ) ;
}
function meridiemFixWrap ( locale , hour , meridiem ) {
var isPm ;
if ( meridiem == null ) {
// nothing to do
return hour ;
}
if ( locale . meridiemHour != null ) {
return locale . meridiemHour ( hour , meridiem ) ;
} else if ( locale . isPM != null ) {
// Fallback
isPm = locale . isPM ( meridiem ) ;
if ( isPm && hour < 12 ) {
hour += 12 ;
}
if ( ! isPm && hour === 12 ) {
hour = 0 ;
}
return hour ;
} else {
// this is not supposed to happen
return hour ;
}
}
// date from string and array of format strings
function configFromStringAndArray ( config ) {
var tempConfig ,
bestMoment ,
scoreToBeat ,
i ,
currentScore ;
if ( config . _f . length === 0 ) {
getParsingFlags ( config ) . invalidFormat = true ;
config . _d = new Date ( NaN ) ;
return ;
}
for ( i = 0 ; i < config . _f . length ; i ++ ) {
currentScore = 0 ;
tempConfig = copyConfig ( { } , config ) ;
if ( config . _useUTC != null ) {
tempConfig . _useUTC = config . _useUTC ;
}
tempConfig . _f = config . _f [ i ] ;
configFromStringAndFormat ( tempConfig ) ;
if ( ! valid _ _isValid ( tempConfig ) ) {
continue ;
}
// if there is any input that was not parsed add a penalty for that format
currentScore += getParsingFlags ( tempConfig ) . charsLeftOver ;
//or tokens
currentScore += getParsingFlags ( tempConfig ) . unusedTokens . length * 10 ;
getParsingFlags ( tempConfig ) . score = currentScore ;
if ( scoreToBeat == null || currentScore < scoreToBeat ) {
scoreToBeat = currentScore ;
bestMoment = tempConfig ;
}
}
extend ( config , bestMoment || tempConfig ) ;
}
function configFromObject ( config ) {
if ( config . _d ) {
return ;
}
var i = normalizeObjectUnits ( config . _i ) ;
config . _a = map ( [ i . year , i . month , i . day || i . date , i . hour , i . minute , i . second , i . millisecond ] , function ( obj ) {
return obj && parseInt ( obj , 10 ) ;
} ) ;
configFromArray ( config ) ;
}
function createFromConfig ( config ) {
var res = new Moment ( checkOverflow ( prepareConfig ( config ) ) ) ;
if ( res . _nextDay ) {
// Adding is smart enough around DST
res . add ( 1 , 'd' ) ;
res . _nextDay = undefined ;
}
return res ;
}
function prepareConfig ( config ) {
var input = config . _i ,
format = config . _f ;
config . _locale = config . _locale || locale _locales _ _getLocale ( config . _l ) ;
if ( input === null || ( format === undefined && input === '' ) ) {
return valid _ _createInvalid ( { nullInput : true } ) ;
}
if ( typeof input === 'string' ) {
config . _i = input = config . _locale . preparse ( input ) ;
}
if ( isMoment ( input ) ) {
return new Moment ( checkOverflow ( input ) ) ;
} else if ( isArray ( format ) ) {
configFromStringAndArray ( config ) ;
} else if ( format ) {
configFromStringAndFormat ( config ) ;
} else if ( isDate ( input ) ) {
config . _d = input ;
} else {
configFromInput ( config ) ;
}
if ( ! valid _ _isValid ( config ) ) {
config . _d = null ;
}
return config ;
}
function configFromInput ( config ) {
var input = config . _i ;
if ( input === undefined ) {
config . _d = new Date ( utils _hooks _ _hooks . now ( ) ) ;
} else if ( isDate ( input ) ) {
config . _d = new Date ( input . valueOf ( ) ) ;
} else if ( typeof input === 'string' ) {
configFromString ( config ) ;
} else if ( isArray ( input ) ) {
config . _a = map ( input . slice ( 0 ) , function ( obj ) {
return parseInt ( obj , 10 ) ;
} ) ;
configFromArray ( config ) ;
} else if ( typeof ( input ) === 'object' ) {
configFromObject ( config ) ;
} else if ( typeof ( input ) === 'number' ) {
// from milliseconds
config . _d = new Date ( input ) ;
} else {
utils _hooks _ _hooks . createFromInputFallback ( config ) ;
}
}
function createLocalOrUTC ( input , format , locale , strict , isUTC ) {
var c = { } ;
if ( typeof ( locale ) === 'boolean' ) {
strict = locale ;
locale = undefined ;
}
// object construction must be done this way.
// https://github.com/moment/moment/issues/1423
c . _isAMomentObject = true ;
c . _useUTC = c . _isUTC = isUTC ;
c . _l = locale ;
c . _i = input ;
c . _f = format ;
c . _strict = strict ;
return createFromConfig ( c ) ;
}
function local _ _createLocal ( input , format , locale , strict ) {
return createLocalOrUTC ( input , format , locale , strict , false ) ;
}
var prototypeMin = deprecate (
'moment().min is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548' ,
function ( ) {
var other = local _ _createLocal . apply ( null , arguments ) ;
if ( this . isValid ( ) && other . isValid ( ) ) {
return other < this ? this : other ;
} else {
return valid _ _createInvalid ( ) ;
}
}
) ;
var prototypeMax = deprecate (
'moment().max is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548' ,
function ( ) {
var other = local _ _createLocal . apply ( null , arguments ) ;
if ( this . isValid ( ) && other . isValid ( ) ) {
return other > this ? this : other ;
} else {
return valid _ _createInvalid ( ) ;
}
}
) ;
// Pick a moment m from moments so that m[fn](other) is true for all
// other. This relies on the function fn to be transitive.
//
// moments should either be an array of moment objects or an array, whose
// first element is an array of moment objects.
function pickBy ( fn , moments ) {
var res , i ;
if ( moments . length === 1 && isArray ( moments [ 0 ] ) ) {
moments = moments [ 0 ] ;
}
if ( ! moments . length ) {
return local _ _createLocal ( ) ;
}
res = moments [ 0 ] ;
for ( i = 1 ; i < moments . length ; ++ i ) {
if ( ! moments [ i ] . isValid ( ) || moments [ i ] [ fn ] ( res ) ) {
res = moments [ i ] ;
}
}
return res ;
}
// TODO: Use [].sort instead?
function min ( ) {
var args = [ ] . slice . call ( arguments , 0 ) ;
return pickBy ( 'isBefore' , args ) ;
}
function max ( ) {
var args = [ ] . slice . call ( arguments , 0 ) ;
return pickBy ( 'isAfter' , args ) ;
}
var now = function ( ) {
return Date . now ? Date . now ( ) : + ( new Date ( ) ) ;
} ;
function Duration ( duration ) {
var normalizedInput = normalizeObjectUnits ( duration ) ,
years = normalizedInput . year || 0 ,
quarters = normalizedInput . quarter || 0 ,
months = normalizedInput . month || 0 ,
weeks = normalizedInput . week || 0 ,
days = normalizedInput . day || 0 ,
hours = normalizedInput . hour || 0 ,
minutes = normalizedInput . minute || 0 ,
seconds = normalizedInput . second || 0 ,
milliseconds = normalizedInput . millisecond || 0 ;
// representation for dateAddRemove
this . _milliseconds = + milliseconds +
seconds * 1e3 + // 1000
minutes * 6e4 + // 1000 * 60
hours * 1000 * 60 * 60 ; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
// Because of dateAddRemove treats 24 hours as different from a
// day when working around DST, we need to store them separately
this . _days = + days +
weeks * 7 ;
// It is impossible translate months into days without knowing
// which months you are are talking about, so we have to store
// it separately.
this . _months = + months +
quarters * 3 +
years * 12 ;
this . _data = { } ;
this . _locale = locale _locales _ _getLocale ( ) ;
this . _bubble ( ) ;
}
function isDuration ( obj ) {
return obj instanceof Duration ;
}
// FORMATTING
function offset ( token , separator ) {
addFormatToken ( token , 0 , 0 , function ( ) {
var offset = this . utcOffset ( ) ;
var sign = '+' ;
if ( offset < 0 ) {
offset = - offset ;
sign = '-' ;
}
return sign + zeroFill ( ~ ~ ( offset / 60 ) , 2 ) + separator + zeroFill ( ~ ~ ( offset ) % 60 , 2 ) ;
} ) ;
}
offset ( 'Z' , ':' ) ;
offset ( 'ZZ' , '' ) ;
// PARSING
addRegexToken ( 'Z' , matchShortOffset ) ;
addRegexToken ( 'ZZ' , matchShortOffset ) ;
addParseToken ( [ 'Z' , 'ZZ' ] , function ( input , array , config ) {
config . _useUTC = true ;
config . _tzm = offsetFromString ( matchShortOffset , input ) ;
} ) ;
// HELPERS
// timezone chunker
// '+10:00' > ['10', '00']
// '-1530' > ['-15', '30']
var chunkOffset = /([\+\-]|\d\d)/gi ;
function offsetFromString ( matcher , string ) {
var matches = ( ( string || '' ) . match ( matcher ) || [ ] ) ;
var chunk = matches [ matches . length - 1 ] || [ ] ;
var parts = ( chunk + '' ) . match ( chunkOffset ) || [ '-' , 0 , 0 ] ;
var minutes = + ( parts [ 1 ] * 60 ) + toInt ( parts [ 2 ] ) ;
return parts [ 0 ] === '+' ? minutes : - minutes ;
}
// Return a moment from input, that is local/utc/zone equivalent to model.
function cloneWithOffset ( input , model ) {
var res , diff ;
if ( model . _isUTC ) {
res = model . clone ( ) ;
diff = ( isMoment ( input ) || isDate ( input ) ? input . valueOf ( ) : local _ _createLocal ( input ) . valueOf ( ) ) - res . valueOf ( ) ;
// Use low-level api, because this fn is low-level api.
res . _d . setTime ( res . _d . valueOf ( ) + diff ) ;
utils _hooks _ _hooks . updateOffset ( res , false ) ;
return res ;
} else {
return local _ _createLocal ( input ) . local ( ) ;
}
}
function getDateOffset ( m ) {
// On Firefox.24 Date#getTimezoneOffset returns a floating point.
// https://github.com/moment/moment/pull/1871
return - Math . round ( m . _d . getTimezoneOffset ( ) / 15 ) * 15 ;
}
// HOOKS
// This function will be called whenever a moment is mutated.
// It is intended to keep the offset in sync with the timezone.
utils _hooks _ _hooks . updateOffset = function ( ) { } ;
// MOMENTS
// keepLocalTime = true means only change the timezone, without
// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
// +0200, so we adjust the time as needed, to be valid.
//
// Keeping the time actually adds/subtracts (one hour)
// from the actual represented time. That is why we call updateOffset
// a second time. In case it wants us to change the offset again
// _changeInProgress == true case, then we have to adjust, because
// there is no such time in the given timezone.
function getSetOffset ( input , keepLocalTime ) {
var offset = this . _offset || 0 ,
localAdjust ;
if ( ! this . isValid ( ) ) {
return input != null ? this : NaN ;
}
if ( input != null ) {
if ( typeof input === 'string' ) {
input = offsetFromString ( matchShortOffset , input ) ;
} else if ( Math . abs ( input ) < 16 ) {
input = input * 60 ;
}
if ( ! this . _isUTC && keepLocalTime ) {
localAdjust = getDateOffset ( this ) ;
}
this . _offset = input ;
this . _isUTC = true ;
if ( localAdjust != null ) {
this . add ( localAdjust , 'm' ) ;
}
if ( offset !== input ) {
if ( ! keepLocalTime || this . _changeInProgress ) {
add _subtract _ _addSubtract ( this , create _ _createDuration ( input - offset , 'm' ) , 1 , false ) ;
} else if ( ! this . _changeInProgress ) {
this . _changeInProgress = true ;
utils _hooks _ _hooks . updateOffset ( this , true ) ;
this . _changeInProgress = null ;
}
}
return this ;
} else {
return this . _isUTC ? offset : getDateOffset ( this ) ;
}
}
function getSetZone ( input , keepLocalTime ) {
if ( input != null ) {
if ( typeof input !== 'string' ) {
input = - input ;
}
this . utcOffset ( input , keepLocalTime ) ;
return this ;
} else {
return - this . utcOffset ( ) ;
}
}
function setOffsetToUTC ( keepLocalTime ) {
return this . utcOffset ( 0 , keepLocalTime ) ;
}
function setOffsetToLocal ( keepLocalTime ) {
if ( this . _isUTC ) {
this . utcOffset ( 0 , keepLocalTime ) ;
this . _isUTC = false ;
if ( keepLocalTime ) {
this . subtract ( getDateOffset ( this ) , 'm' ) ;
}
}
return this ;
}
function setOffsetToParsedOffset ( ) {
if ( this . _tzm ) {
this . utcOffset ( this . _tzm ) ;
} else if ( typeof this . _i === 'string' ) {
this . utcOffset ( offsetFromString ( matchOffset , this . _i ) ) ;
}
return this ;
}
function hasAlignedHourOffset ( input ) {
if ( ! this . isValid ( ) ) {
return false ;
}
input = input ? local _ _createLocal ( input ) . utcOffset ( ) : 0 ;
return ( this . utcOffset ( ) - input ) % 60 === 0 ;
}
function isDaylightSavingTime ( ) {
return (
this . utcOffset ( ) > this . clone ( ) . month ( 0 ) . utcOffset ( ) ||
this . utcOffset ( ) > this . clone ( ) . month ( 5 ) . utcOffset ( )
) ;
}
function isDaylightSavingTimeShifted ( ) {
if ( ! isUndefined ( this . _isDSTShifted ) ) {
return this . _isDSTShifted ;
}
var c = { } ;
copyConfig ( c , this ) ;
c = prepareConfig ( c ) ;
if ( c . _a ) {
var other = c . _isUTC ? create _utc _ _createUTC ( c . _a ) : local _ _createLocal ( c . _a ) ;
this . _isDSTShifted = this . isValid ( ) &&
compareArrays ( c . _a , other . toArray ( ) ) > 0 ;
} else {
this . _isDSTShifted = false ;
}
return this . _isDSTShifted ;
}
function isLocal ( ) {
return this . isValid ( ) ? ! this . _isUTC : false ;
}
function isUtcOffset ( ) {
return this . isValid ( ) ? this . _isUTC : false ;
}
function isUtc ( ) {
return this . isValid ( ) ? this . _isUTC && this . _offset === 0 : false ;
}
// ASP.NET json date format regex
var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/ ;
// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
// and further modified to allow for strings containing both week and day
var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/ ;
function create _ _createDuration ( input , key ) {
var duration = input ,
// matching against regexp is expensive, do it on demand
match = null ,
sign ,
ret ,
diffRes ;
if ( isDuration ( input ) ) {
duration = {
ms : input . _milliseconds ,
d : input . _days ,
M : input . _months
} ;
} else if ( typeof input === 'number' ) {
duration = { } ;
if ( key ) {
duration [ key ] = input ;
} else {
duration . milliseconds = input ;
}
} else if ( ! ! ( match = aspNetRegex . exec ( input ) ) ) {
sign = ( match [ 1 ] === '-' ) ? - 1 : 1 ;
duration = {
y : 0 ,
d : toInt ( match [ DATE ] ) * sign ,
h : toInt ( match [ HOUR ] ) * sign ,
m : toInt ( match [ MINUTE ] ) * sign ,
s : toInt ( match [ SECOND ] ) * sign ,
ms : toInt ( match [ MILLISECOND ] ) * sign
} ;
} else if ( ! ! ( match = isoRegex . exec ( input ) ) ) {
sign = ( match [ 1 ] === '-' ) ? - 1 : 1 ;
duration = {
y : parseIso ( match [ 2 ] , sign ) ,
M : parseIso ( match [ 3 ] , sign ) ,
w : parseIso ( match [ 4 ] , sign ) ,
d : parseIso ( match [ 5 ] , sign ) ,
h : parseIso ( match [ 6 ] , sign ) ,
m : parseIso ( match [ 7 ] , sign ) ,
s : parseIso ( match [ 8 ] , sign )
} ;
} else if ( duration == null ) { // checks for null or undefined
duration = { } ;
} else if ( typeof duration === 'object' && ( 'from' in duration || 'to' in duration ) ) {
diffRes = momentsDifference ( local _ _createLocal ( duration . from ) , local _ _createLocal ( duration . to ) ) ;
duration = { } ;
duration . ms = diffRes . milliseconds ;
duration . M = diffRes . months ;
}
ret = new Duration ( duration ) ;
if ( isDuration ( input ) && hasOwnProp ( input , '_locale' ) ) {
ret . _locale = input . _locale ;
}
return ret ;
}
create _ _createDuration . fn = Duration . prototype ;
function parseIso ( inp , sign ) {
// We'd normally use ~~inp for this, but unfortunately it also
// converts floats to ints.
// inp may be undefined, so careful calling replace on it.
var res = inp && parseFloat ( inp . replace ( ',' , '.' ) ) ;
// apply sign while we're at it
return ( isNaN ( res ) ? 0 : res ) * sign ;
}
function positiveMomentsDifference ( base , other ) {
var res = { milliseconds : 0 , months : 0 } ;
res . months = other . month ( ) - base . month ( ) +
( other . year ( ) - base . year ( ) ) * 12 ;
if ( base . clone ( ) . add ( res . months , 'M' ) . isAfter ( other ) ) {
-- res . months ;
}
res . milliseconds = + other - + ( base . clone ( ) . add ( res . months , 'M' ) ) ;
return res ;
}
function momentsDifference ( base , other ) {
var res ;
if ( ! ( base . isValid ( ) && other . isValid ( ) ) ) {
return { milliseconds : 0 , months : 0 } ;
}
other = cloneWithOffset ( other , base ) ;
if ( base . isBefore ( other ) ) {
res = positiveMomentsDifference ( base , other ) ;
} else {
res = positiveMomentsDifference ( other , base ) ;
res . milliseconds = - res . milliseconds ;
res . months = - res . months ;
}
return res ;
}
function absRound ( number ) {
if ( number < 0 ) {
return Math . round ( - 1 * number ) * - 1 ;
} else {
return Math . round ( number ) ;
}
}
// TODO: remove 'name' arg after deprecation is removed
function createAdder ( direction , name ) {
return function ( val , period ) {
var dur , tmp ;
//invert the arguments, but complain about it
if ( period !== null && ! isNaN ( + period ) ) {
deprecateSimple ( name , 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).' ) ;
tmp = val ; val = period ; period = tmp ;
}
val = typeof val === 'string' ? + val : val ;
dur = create _ _createDuration ( val , period ) ;
add _subtract _ _addSubtract ( this , dur , direction ) ;
return this ;
} ;
}
function add _subtract _ _addSubtract ( mom , duration , isAdding , updateOffset ) {
var milliseconds = duration . _milliseconds ,
days = absRound ( duration . _days ) ,
months = absRound ( duration . _months ) ;
if ( ! mom . isValid ( ) ) {
// No op
return ;
}
updateOffset = updateOffset == null ? true : updateOffset ;
if ( milliseconds ) {
mom . _d . setTime ( mom . _d . valueOf ( ) + milliseconds * isAdding ) ;
}
if ( days ) {
get _set _ _set ( mom , 'Date' , get _set _ _get ( mom , 'Date' ) + days * isAdding ) ;
}
if ( months ) {
setMonth ( mom , get _set _ _get ( mom , 'Month' ) + months * isAdding ) ;
}
if ( updateOffset ) {
utils _hooks _ _hooks . updateOffset ( mom , days || months ) ;
}
}
var add _subtract _ _add = createAdder ( 1 , 'add' ) ;
var add _subtract _ _subtract = createAdder ( - 1 , 'subtract' ) ;
function moment _calendar _ _calendar ( time , formats ) {
// We want to compare the start of today, vs this.
// Getting start-of-today depends on whether we're local/utc/offset or not.
var now = time || local _ _createLocal ( ) ,
sod = cloneWithOffset ( now , this ) . startOf ( 'day' ) ,
diff = this . diff ( sod , 'days' , true ) ,
format = diff < - 6 ? 'sameElse' :
diff < - 1 ? 'lastWeek' :
diff < 0 ? 'lastDay' :
diff < 1 ? 'sameDay' :
diff < 2 ? 'nextDay' :
diff < 7 ? 'nextWeek' : 'sameElse' ;
var output = formats && ( isFunction ( formats [ format ] ) ? formats [ format ] ( ) : formats [ format ] ) ;
return this . format ( output || this . localeData ( ) . calendar ( format , this , local _ _createLocal ( now ) ) ) ;
}
function clone ( ) {
return new Moment ( this ) ;
}
function isAfter ( input , units ) {
var localInput = isMoment ( input ) ? input : local _ _createLocal ( input ) ;
if ( ! ( this . isValid ( ) && localInput . isValid ( ) ) ) {
return false ;
}
units = normalizeUnits ( ! isUndefined ( units ) ? units : 'millisecond' ) ;
if ( units === 'millisecond' ) {
return this . valueOf ( ) > localInput . valueOf ( ) ;
} else {
return localInput . valueOf ( ) < this . clone ( ) . startOf ( units ) . valueOf ( ) ;
}
}
function isBefore ( input , units ) {
var localInput = isMoment ( input ) ? input : local _ _createLocal ( input ) ;
if ( ! ( this . isValid ( ) && localInput . isValid ( ) ) ) {
return false ;
}
units = normalizeUnits ( ! isUndefined ( units ) ? units : 'millisecond' ) ;
if ( units === 'millisecond' ) {
return this . valueOf ( ) < localInput . valueOf ( ) ;
} else {
return this . clone ( ) . endOf ( units ) . valueOf ( ) < localInput . valueOf ( ) ;
}
}
function isBetween ( from , to , units , inclusivity ) {
inclusivity = inclusivity || '()' ;
return ( inclusivity [ 0 ] === '(' ? this . isAfter ( from , units ) : ! this . isBefore ( from , units ) ) &&
( inclusivity [ 1 ] === ')' ? this . isBefore ( to , units ) : ! this . isAfter ( to , units ) ) ;
}
function isSame ( input , units ) {
var localInput = isMoment ( input ) ? input : local _ _createLocal ( input ) ,
inputMs ;
if ( ! ( this . isValid ( ) && localInput . isValid ( ) ) ) {
return false ;
}
units = normalizeUnits ( units || 'millisecond' ) ;
if ( units === 'millisecond' ) {
return this . valueOf ( ) === localInput . valueOf ( ) ;
} else {
inputMs = localInput . valueOf ( ) ;
return this . clone ( ) . startOf ( units ) . valueOf ( ) <= inputMs && inputMs <= this . clone ( ) . endOf ( units ) . valueOf ( ) ;
}
}
function isSameOrAfter ( input , units ) {
return this . isSame ( input , units ) || this . isAfter ( input , units ) ;
}
function isSameOrBefore ( input , units ) {
return this . isSame ( input , units ) || this . isBefore ( input , units ) ;
}
function diff ( input , units , asFloat ) {
var that ,
zoneDelta ,
delta , output ;
if ( ! this . isValid ( ) ) {
return NaN ;
}
that = cloneWithOffset ( input , this ) ;
if ( ! that . isValid ( ) ) {
return NaN ;
}
zoneDelta = ( that . utcOffset ( ) - this . utcOffset ( ) ) * 6e4 ;
units = normalizeUnits ( units ) ;
if ( units === 'year' || units === 'month' || units === 'quarter' ) {
output = monthDiff ( this , that ) ;
if ( units === 'quarter' ) {
output = output / 3 ;
} else if ( units === 'year' ) {
output = output / 12 ;
}
} else {
delta = this - that ;
output = units === 'second' ? delta / 1e3 : // 1000
units === 'minute' ? delta / 6e4 : // 1000 * 60
units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
units === 'day' ? ( delta - zoneDelta ) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
units === 'week' ? ( delta - zoneDelta ) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
delta ;
}
return asFloat ? output : absFloor ( output ) ;
}
function monthDiff ( a , b ) {
// difference in months
var wholeMonthDiff = ( ( b . year ( ) - a . year ( ) ) * 12 ) + ( b . month ( ) - a . month ( ) ) ,
// b is in (anchor - 1 month, anchor + 1 month)
anchor = a . clone ( ) . add ( wholeMonthDiff , 'months' ) ,
anchor2 , adjust ;
if ( b - anchor < 0 ) {
anchor2 = a . clone ( ) . add ( wholeMonthDiff - 1 , 'months' ) ;
// linear across the month
adjust = ( b - anchor ) / ( anchor - anchor2 ) ;
} else {
anchor2 = a . clone ( ) . add ( wholeMonthDiff + 1 , 'months' ) ;
// linear across the month
adjust = ( b - anchor ) / ( anchor2 - anchor ) ;
}
//check for negative zero, return zero if negative zero
return - ( wholeMonthDiff + adjust ) || 0 ;
}
utils _hooks _ _hooks . defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ' ;
utils _hooks _ _hooks . defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]' ;
function toString ( ) {
return this . clone ( ) . locale ( 'en' ) . format ( 'ddd MMM DD YYYY HH:mm:ss [GMT]ZZ' ) ;
}
function moment _format _ _toISOString ( ) {
var m = this . clone ( ) . utc ( ) ;
if ( 0 < m . year ( ) && m . year ( ) <= 9999 ) {
if ( isFunction ( Date . prototype . toISOString ) ) {
// native implementation is ~50x faster, use it when we can
return this . toDate ( ) . toISOString ( ) ;
} else {
return formatMoment ( m , 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' ) ;
}
} else {
return formatMoment ( m , 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' ) ;
}
}
function format ( inputString ) {
if ( ! inputString ) {
inputString = this . isUtc ( ) ? utils _hooks _ _hooks . defaultFormatUtc : utils _hooks _ _hooks . defaultFormat ;
}
var output = formatMoment ( this , inputString ) ;
return this . localeData ( ) . postformat ( output ) ;
}
function from ( time , withoutSuffix ) {
if ( this . isValid ( ) &&
( ( isMoment ( time ) && time . isValid ( ) ) ||
local _ _createLocal ( time ) . isValid ( ) ) ) {
return create _ _createDuration ( { to : this , from : time } ) . locale ( this . locale ( ) ) . humanize ( ! withoutSuffix ) ;
} else {
return this . localeData ( ) . invalidDate ( ) ;
}
}
function fromNow ( withoutSuffix ) {
return this . from ( local _ _createLocal ( ) , withoutSuffix ) ;
}
function to ( time , withoutSuffix ) {
if ( this . isValid ( ) &&
( ( isMoment ( time ) && time . isValid ( ) ) ||
local _ _createLocal ( time ) . isValid ( ) ) ) {
return create _ _createDuration ( { from : this , to : time } ) . locale ( this . locale ( ) ) . humanize ( ! withoutSuffix ) ;
} else {
return this . localeData ( ) . invalidDate ( ) ;
}
}
function toNow ( withoutSuffix ) {
return this . to ( local _ _createLocal ( ) , withoutSuffix ) ;
}
// If passed a locale key, it will set the locale for this
// instance. Otherwise, it will return the locale configuration
// variables for this instance.
function locale ( key ) {
var newLocaleData ;
if ( key === undefined ) {
return this . _locale . _abbr ;
} else {
newLocaleData = locale _locales _ _getLocale ( key ) ;
if ( newLocaleData != null ) {
this . _locale = newLocaleData ;
}
return this ;
}
}
var lang = deprecate (
'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.' ,
function ( key ) {
if ( key === undefined ) {
return this . localeData ( ) ;
} else {
return this . locale ( key ) ;
}
}
) ;
function localeData ( ) {
return this . _locale ;
}
function startOf ( units ) {
units = normalizeUnits ( units ) ;
// the following switch intentionally omits break keywords
// to utilize falling through the cases.
switch ( units ) {
case 'year' :
this . month ( 0 ) ;
/* falls through */
case 'quarter' :
case 'month' :
this . date ( 1 ) ;
/* falls through */
case 'week' :
case 'isoWeek' :
case 'day' :
case 'date' :
this . hours ( 0 ) ;
/* falls through */
case 'hour' :
this . minutes ( 0 ) ;
/* falls through */
case 'minute' :
this . seconds ( 0 ) ;
/* falls through */
case 'second' :
this . milliseconds ( 0 ) ;
}
// weeks are a special case
if ( units === 'week' ) {
this . weekday ( 0 ) ;
}
if ( units === 'isoWeek' ) {
this . isoWeekday ( 1 ) ;
}
// quarters are also special
if ( units === 'quarter' ) {
this . month ( Math . floor ( this . month ( ) / 3 ) * 3 ) ;
}
return this ;
}
function endOf ( units ) {
units = normalizeUnits ( units ) ;
if ( units === undefined || units === 'millisecond' ) {
return this ;
}
// 'date' is an alias for 'day', so it should be considered as such.
if ( units === 'date' ) {
units = 'day' ;
}
return this . startOf ( units ) . add ( 1 , ( units === 'isoWeek' ? 'week' : units ) ) . subtract ( 1 , 'ms' ) ;
}
function to _type _ _valueOf ( ) {
return this . _d . valueOf ( ) - ( ( this . _offset || 0 ) * 60000 ) ;
}
function unix ( ) {
return Math . floor ( this . valueOf ( ) / 1000 ) ;
}
function toDate ( ) {
return this . _offset ? new Date ( this . valueOf ( ) ) : this . _d ;
}
function toArray ( ) {
var m = this ;
return [ m . year ( ) , m . month ( ) , m . date ( ) , m . hour ( ) , m . minute ( ) , m . second ( ) , m . millisecond ( ) ] ;
}
function toObject ( ) {
var m = this ;
return {
years : m . year ( ) ,
months : m . month ( ) ,
date : m . date ( ) ,
hours : m . hours ( ) ,
minutes : m . minutes ( ) ,
seconds : m . seconds ( ) ,
milliseconds : m . milliseconds ( )
} ;
}
function toJSON ( ) {
// new Date(NaN).toJSON() === null
return this . isValid ( ) ? this . toISOString ( ) : null ;
}
function moment _valid _ _isValid ( ) {
return valid _ _isValid ( this ) ;
}
function parsingFlags ( ) {
return extend ( { } , getParsingFlags ( this ) ) ;
}
function invalidAt ( ) {
return getParsingFlags ( this ) . overflow ;
}
function creationData ( ) {
return {
input : this . _i ,
format : this . _f ,
locale : this . _locale ,
isUTC : this . _isUTC ,
strict : this . _strict
} ;
}
// FORMATTING
addFormatToken ( 0 , [ 'gg' , 2 ] , 0 , function ( ) {
return this . weekYear ( ) % 100 ;
} ) ;
addFormatToken ( 0 , [ 'GG' , 2 ] , 0 , function ( ) {
return this . isoWeekYear ( ) % 100 ;
} ) ;
function addWeekYearFormatToken ( token , getter ) {
addFormatToken ( 0 , [ token , token . length ] , 0 , getter ) ;
}
addWeekYearFormatToken ( 'gggg' , 'weekYear' ) ;
addWeekYearFormatToken ( 'ggggg' , 'weekYear' ) ;
addWeekYearFormatToken ( 'GGGG' , 'isoWeekYear' ) ;
addWeekYearFormatToken ( 'GGGGG' , 'isoWeekYear' ) ;
// ALIASES
addUnitAlias ( 'weekYear' , 'gg' ) ;
addUnitAlias ( 'isoWeekYear' , 'GG' ) ;
// PARSING
addRegexToken ( 'G' , matchSigned ) ;
addRegexToken ( 'g' , matchSigned ) ;
addRegexToken ( 'GG' , match1to2 , match2 ) ;
addRegexToken ( 'gg' , match1to2 , match2 ) ;
addRegexToken ( 'GGGG' , match1to4 , match4 ) ;
addRegexToken ( 'gggg' , match1to4 , match4 ) ;
addRegexToken ( 'GGGGG' , match1to6 , match6 ) ;
addRegexToken ( 'ggggg' , match1to6 , match6 ) ;
addWeekParseToken ( [ 'gggg' , 'ggggg' , 'GGGG' , 'GGGGG' ] , function ( input , week , config , token ) {
week [ token . substr ( 0 , 2 ) ] = toInt ( input ) ;
} ) ;
addWeekParseToken ( [ 'gg' , 'GG' ] , function ( input , week , config , token ) {
week [ token ] = utils _hooks _ _hooks . parseTwoDigitYear ( input ) ;
} ) ;
// MOMENTS
function getSetWeekYear ( input ) {
return getSetWeekYearHelper . call ( this ,
input ,
this . week ( ) ,
this . weekday ( ) ,
this . localeData ( ) . _week . dow ,
this . localeData ( ) . _week . doy ) ;
}
function getSetISOWeekYear ( input ) {
return getSetWeekYearHelper . call ( this ,
input , this . isoWeek ( ) , this . isoWeekday ( ) , 1 , 4 ) ;
}
function getISOWeeksInYear ( ) {
return weeksInYear ( this . year ( ) , 1 , 4 ) ;
}
function getWeeksInYear ( ) {
var weekInfo = this . localeData ( ) . _week ;
return weeksInYear ( this . year ( ) , weekInfo . dow , weekInfo . doy ) ;
}
function getSetWeekYearHelper ( input , week , weekday , dow , doy ) {
var weeksTarget ;
if ( input == null ) {
return weekOfYear ( this , dow , doy ) . year ;
} else {
weeksTarget = weeksInYear ( input , dow , doy ) ;
if ( week > weeksTarget ) {
week = weeksTarget ;
}
return setWeekAll . call ( this , input , week , weekday , dow , doy ) ;
}
}
function setWeekAll ( weekYear , week , weekday , dow , doy ) {
var dayOfYearData = dayOfYearFromWeeks ( weekYear , week , weekday , dow , doy ) ,
date = createUTCDate ( dayOfYearData . year , 0 , dayOfYearData . dayOfYear ) ;
this . year ( date . getUTCFullYear ( ) ) ;
this . month ( date . getUTCMonth ( ) ) ;
this . date ( date . getUTCDate ( ) ) ;
return this ;
}
// FORMATTING
addFormatToken ( 'Q' , 0 , 'Qo' , 'quarter' ) ;
// ALIASES
addUnitAlias ( 'quarter' , 'Q' ) ;
// PARSING
addRegexToken ( 'Q' , match1 ) ;
addParseToken ( 'Q' , function ( input , array ) {
array [ MONTH ] = ( toInt ( input ) - 1 ) * 3 ;
} ) ;
// MOMENTS
function getSetQuarter ( input ) {
return input == null ? Math . ceil ( ( this . month ( ) + 1 ) / 3 ) : this . month ( ( input - 1 ) * 3 + this . month ( ) % 3 ) ;
}
// FORMATTING
addFormatToken ( 'w' , [ 'ww' , 2 ] , 'wo' , 'week' ) ;
addFormatToken ( 'W' , [ 'WW' , 2 ] , 'Wo' , 'isoWeek' ) ;
// ALIASES
addUnitAlias ( 'week' , 'w' ) ;
addUnitAlias ( 'isoWeek' , 'W' ) ;
// PARSING
addRegexToken ( 'w' , match1to2 ) ;
addRegexToken ( 'ww' , match1to2 , match2 ) ;
addRegexToken ( 'W' , match1to2 ) ;
addRegexToken ( 'WW' , match1to2 , match2 ) ;
addWeekParseToken ( [ 'w' , 'ww' , 'W' , 'WW' ] , function ( input , week , config , token ) {
week [ token . substr ( 0 , 1 ) ] = toInt ( input ) ;
} ) ;
// HELPERS
// LOCALES
function localeWeek ( mom ) {
return weekOfYear ( mom , this . _week . dow , this . _week . doy ) . week ;
}
var defaultLocaleWeek = {
dow : 0 , // Sunday is the first day of the week.
doy : 6 // The week that contains Jan 1st is the first week of the year.
} ;
function localeFirstDayOfWeek ( ) {
return this . _week . dow ;
}
function localeFirstDayOfYear ( ) {
return this . _week . doy ;
}
// MOMENTS
function getSetWeek ( input ) {
var week = this . localeData ( ) . week ( this ) ;
return input == null ? week : this . add ( ( input - week ) * 7 , 'd' ) ;
}
function getSetISOWeek ( input ) {
var week = weekOfYear ( this , 1 , 4 ) . week ;
return input == null ? week : this . add ( ( input - week ) * 7 , 'd' ) ;
}
// FORMATTING
addFormatToken ( 'D' , [ 'DD' , 2 ] , 'Do' , 'date' ) ;
// ALIASES
addUnitAlias ( 'date' , 'D' ) ;
// PARSING
addRegexToken ( 'D' , match1to2 ) ;
addRegexToken ( 'DD' , match1to2 , match2 ) ;
addRegexToken ( 'Do' , function ( isStrict , locale ) {
return isStrict ? locale . _ordinalParse : locale . _ordinalParseLenient ;
} ) ;
addParseToken ( [ 'D' , 'DD' ] , DATE ) ;
addParseToken ( 'Do' , function ( input , array ) {
array [ DATE ] = toInt ( input . match ( match1to2 ) [ 0 ] , 10 ) ;
} ) ;
// MOMENTS
var getSetDayOfMonth = makeGetSet ( 'Date' , true ) ;
// FORMATTING
addFormatToken ( 'd' , 0 , 'do' , 'day' ) ;
addFormatToken ( 'dd' , 0 , 0 , function ( format ) {
return this . localeData ( ) . weekdaysMin ( this , format ) ;
} ) ;
addFormatToken ( 'ddd' , 0 , 0 , function ( format ) {
return this . localeData ( ) . weekdaysShort ( this , format ) ;
} ) ;
addFormatToken ( 'dddd' , 0 , 0 , function ( format ) {
return this . localeData ( ) . weekdays ( this , format ) ;
} ) ;
addFormatToken ( 'e' , 0 , 0 , 'weekday' ) ;
addFormatToken ( 'E' , 0 , 0 , 'isoWeekday' ) ;
// ALIASES
addUnitAlias ( 'day' , 'd' ) ;
addUnitAlias ( 'weekday' , 'e' ) ;
addUnitAlias ( 'isoWeekday' , 'E' ) ;
// PARSING
addRegexToken ( 'd' , match1to2 ) ;
addRegexToken ( 'e' , match1to2 ) ;
addRegexToken ( 'E' , match1to2 ) ;
addRegexToken ( 'dd' , function ( isStrict , locale ) {
return locale . weekdaysMinRegex ( isStrict ) ;
} ) ;
addRegexToken ( 'ddd' , function ( isStrict , locale ) {
return locale . weekdaysShortRegex ( isStrict ) ;
} ) ;
addRegexToken ( 'dddd' , function ( isStrict , locale ) {
return locale . weekdaysRegex ( isStrict ) ;
} ) ;
addWeekParseToken ( [ 'dd' , 'ddd' , 'dddd' ] , function ( input , week , config , token ) {
var weekday = config . _locale . weekdaysParse ( input , token , config . _strict ) ;
// if we didn't get a weekday name, mark the date as invalid
if ( weekday != null ) {
week . d = weekday ;
} else {
getParsingFlags ( config ) . invalidWeekday = input ;
}
} ) ;
addWeekParseToken ( [ 'd' , 'e' , 'E' ] , function ( input , week , config , token ) {
week [ token ] = toInt ( input ) ;
} ) ;
// HELPERS
function parseWeekday ( input , locale ) {
if ( typeof input !== 'string' ) {
return input ;
}
if ( ! isNaN ( input ) ) {
return parseInt ( input , 10 ) ;
}
input = locale . weekdaysParse ( input ) ;
if ( typeof input === 'number' ) {
return input ;
}
return null ;
}
// LOCALES
var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday' . split ( '_' ) ;
function localeWeekdays ( m , format ) {
return isArray ( this . _weekdays ) ? this . _weekdays [ m . day ( ) ] :
this . _weekdays [ this . _weekdays . isFormat . test ( format ) ? 'format' : 'standalone' ] [ m . day ( ) ] ;
}
var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat' . split ( '_' ) ;
function localeWeekdaysShort ( m ) {
return this . _weekdaysShort [ m . day ( ) ] ;
}
var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa' . split ( '_' ) ;
function localeWeekdaysMin ( m ) {
return this . _weekdaysMin [ m . day ( ) ] ;
}
function day _of _week _ _handleStrictParse ( weekdayName , format , strict ) {
var i , ii , mom , llc = weekdayName . toLocaleLowerCase ( ) ;
if ( ! this . _weekdaysParse ) {
this . _weekdaysParse = [ ] ;
this . _shortWeekdaysParse = [ ] ;
this . _minWeekdaysParse = [ ] ;
for ( i = 0 ; i < 7 ; ++ i ) {
mom = create _utc _ _createUTC ( [ 2000 , 1 ] ) . day ( i ) ;
this . _minWeekdaysParse [ i ] = this . weekdaysMin ( mom , '' ) . toLocaleLowerCase ( ) ;
this . _shortWeekdaysParse [ i ] = this . weekdaysShort ( mom , '' ) . toLocaleLowerCase ( ) ;
this . _weekdaysParse [ i ] = this . weekdays ( mom , '' ) . toLocaleLowerCase ( ) ;
}
}
if ( strict ) {
if ( format === 'dddd' ) {
ii = indexOf . call ( this . _weekdaysParse , llc ) ;
return ii !== - 1 ? ii : null ;
} else if ( format === 'ddd' ) {
ii = indexOf . call ( this . _shortWeekdaysParse , llc ) ;
return ii !== - 1 ? ii : null ;
} else {
ii = indexOf . call ( this . _minWeekdaysParse , llc ) ;
return ii !== - 1 ? ii : null ;
}
} else {
if ( format === 'dddd' ) {
ii = indexOf . call ( this . _weekdaysParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _shortWeekdaysParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _minWeekdaysParse , llc ) ;
return ii !== - 1 ? ii : null ;
} else if ( format === 'ddd' ) {
ii = indexOf . call ( this . _shortWeekdaysParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _weekdaysParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _minWeekdaysParse , llc ) ;
return ii !== - 1 ? ii : null ;
} else {
ii = indexOf . call ( this . _minWeekdaysParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _weekdaysParse , llc ) ;
if ( ii !== - 1 ) {
return ii ;
}
ii = indexOf . call ( this . _shortWeekdaysParse , llc ) ;
return ii !== - 1 ? ii : null ;
}
}
}
function localeWeekdaysParse ( weekdayName , format , strict ) {
var i , mom , regex ;
if ( this . _weekdaysParseExact ) {
return day _of _week _ _handleStrictParse . call ( this , weekdayName , format , strict ) ;
}
if ( ! this . _weekdaysParse ) {
this . _weekdaysParse = [ ] ;
this . _minWeekdaysParse = [ ] ;
this . _shortWeekdaysParse = [ ] ;
this . _fullWeekdaysParse = [ ] ;
}
for ( i = 0 ; i < 7 ; i ++ ) {
// make the regex if we don't have it already
mom = create _utc _ _createUTC ( [ 2000 , 1 ] ) . day ( i ) ;
if ( strict && ! this . _fullWeekdaysParse [ i ] ) {
this . _fullWeekdaysParse [ i ] = new RegExp ( '^' + this . weekdays ( mom , '' ) . replace ( '.' , '\.?' ) + '$' , 'i' ) ;
this . _shortWeekdaysParse [ i ] = new RegExp ( '^' + this . weekdaysShort ( mom , '' ) . replace ( '.' , '\.?' ) + '$' , 'i' ) ;
this . _minWeekdaysParse [ i ] = new RegExp ( '^' + this . weekdaysMin ( mom , '' ) . replace ( '.' , '\.?' ) + '$' , 'i' ) ;
}
if ( ! this . _weekdaysParse [ i ] ) {
regex = '^' + this . weekdays ( mom , '' ) + '|^' + this . weekdaysShort ( mom , '' ) + '|^' + this . weekdaysMin ( mom , '' ) ;
this . _weekdaysParse [ i ] = new RegExp ( regex . replace ( '.' , '' ) , 'i' ) ;
}
// test the regex
if ( strict && format === 'dddd' && this . _fullWeekdaysParse [ i ] . test ( weekdayName ) ) {
return i ;
} else if ( strict && format === 'ddd' && this . _shortWeekdaysParse [ i ] . test ( weekdayName ) ) {
return i ;
} else if ( strict && format === 'dd' && this . _minWeekdaysParse [ i ] . test ( weekdayName ) ) {
return i ;
} else if ( ! strict && this . _weekdaysParse [ i ] . test ( weekdayName ) ) {
return i ;
}
}
}
// MOMENTS
function getSetDayOfWeek ( input ) {
if ( ! this . isValid ( ) ) {
return input != null ? this : NaN ;
}
var day = this . _isUTC ? this . _d . getUTCDay ( ) : this . _d . getDay ( ) ;
if ( input != null ) {
input = parseWeekday ( input , this . localeData ( ) ) ;
return this . add ( input - day , 'd' ) ;
} else {
return day ;
}
}
function getSetLocaleDayOfWeek ( input ) {
if ( ! this . isValid ( ) ) {
return input != null ? this : NaN ;
}
var weekday = ( this . day ( ) + 7 - this . localeData ( ) . _week . dow ) % 7 ;
return input == null ? weekday : this . add ( input - weekday , 'd' ) ;
}
function getSetISODayOfWeek ( input ) {
if ( ! this . isValid ( ) ) {
return input != null ? this : NaN ;
}
// behaves the same as moment#day except
// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
// as a setter, sunday should belong to the previous week.
return input == null ? this . day ( ) || 7 : this . day ( this . day ( ) % 7 ? input : input - 7 ) ;
}
var defaultWeekdaysRegex = matchWord ;
function weekdaysRegex ( isStrict ) {
if ( this . _weekdaysParseExact ) {
if ( ! hasOwnProp ( this , '_weekdaysRegex' ) ) {
computeWeekdaysParse . call ( this ) ;
}
if ( isStrict ) {
return this . _weekdaysStrictRegex ;
} else {
return this . _weekdaysRegex ;
}
} else {
return this . _weekdaysStrictRegex && isStrict ?
this . _weekdaysStrictRegex : this . _weekdaysRegex ;
}
}
var defaultWeekdaysShortRegex = matchWord ;
function weekdaysShortRegex ( isStrict ) {
if ( this . _weekdaysParseExact ) {
if ( ! hasOwnProp ( this , '_weekdaysRegex' ) ) {
computeWeekdaysParse . call ( this ) ;
}
if ( isStrict ) {
return this . _weekdaysShortStrictRegex ;
} else {
return this . _weekdaysShortRegex ;
}
} else {
return this . _weekdaysShortStrictRegex && isStrict ?
this . _weekdaysShortStrictRegex : this . _weekdaysShortRegex ;
}
}
var defaultWeekdaysMinRegex = matchWord ;
function weekdaysMinRegex ( isStrict ) {
if ( this . _weekdaysParseExact ) {
if ( ! hasOwnProp ( this , '_weekdaysRegex' ) ) {
computeWeekdaysParse . call ( this ) ;
}
if ( isStrict ) {
return this . _weekdaysMinStrictRegex ;
} else {
return this . _weekdaysMinRegex ;
}
} else {
return this . _weekdaysMinStrictRegex && isStrict ?
this . _weekdaysMinStrictRegex : this . _weekdaysMinRegex ;
}
}
function computeWeekdaysParse ( ) {
function cmpLenRev ( a , b ) {
return b . length - a . length ;
}
var minPieces = [ ] , shortPieces = [ ] , longPieces = [ ] , mixedPieces = [ ] ,
i , mom , minp , shortp , longp ;
for ( i = 0 ; i < 7 ; i ++ ) {
// make the regex if we don't have it already
mom = create _utc _ _createUTC ( [ 2000 , 1 ] ) . day ( i ) ;
minp = this . weekdaysMin ( mom , '' ) ;
shortp = this . weekdaysShort ( mom , '' ) ;
longp = this . weekdays ( mom , '' ) ;
minPieces . push ( minp ) ;
shortPieces . push ( shortp ) ;
longPieces . push ( longp ) ;
mixedPieces . push ( minp ) ;
mixedPieces . push ( shortp ) ;
mixedPieces . push ( longp ) ;
}
// Sorting makes sure if one weekday (or abbr) is a prefix of another it
// will match the longer piece.
minPieces . sort ( cmpLenRev ) ;
shortPieces . sort ( cmpLenRev ) ;
longPieces . sort ( cmpLenRev ) ;
mixedPieces . sort ( cmpLenRev ) ;
for ( i = 0 ; i < 7 ; i ++ ) {
shortPieces [ i ] = regexEscape ( shortPieces [ i ] ) ;
longPieces [ i ] = regexEscape ( longPieces [ i ] ) ;
mixedPieces [ i ] = regexEscape ( mixedPieces [ i ] ) ;
}
this . _weekdaysRegex = new RegExp ( '^(' + mixedPieces . join ( '|' ) + ')' , 'i' ) ;
this . _weekdaysShortRegex = this . _weekdaysRegex ;
this . _weekdaysMinRegex = this . _weekdaysRegex ;
this . _weekdaysStrictRegex = new RegExp ( '^(' + longPieces . join ( '|' ) + ')' , 'i' ) ;
this . _weekdaysShortStrictRegex = new RegExp ( '^(' + shortPieces . join ( '|' ) + ')' , 'i' ) ;
this . _weekdaysMinStrictRegex = new RegExp ( '^(' + minPieces . join ( '|' ) + ')' , 'i' ) ;
}
// FORMATTING
addFormatToken ( 'DDD' , [ 'DDDD' , 3 ] , 'DDDo' , 'dayOfYear' ) ;
// ALIASES
addUnitAlias ( 'dayOfYear' , 'DDD' ) ;
// PARSING
addRegexToken ( 'DDD' , match1to3 ) ;
addRegexToken ( 'DDDD' , match3 ) ;
addParseToken ( [ 'DDD' , 'DDDD' ] , function ( input , array , config ) {
config . _dayOfYear = toInt ( input ) ;
} ) ;
// HELPERS
// MOMENTS
function getSetDayOfYear ( input ) {
var dayOfYear = Math . round ( ( this . clone ( ) . startOf ( 'day' ) - this . clone ( ) . startOf ( 'year' ) ) / 864e5 ) + 1 ;
return input == null ? dayOfYear : this . add ( ( input - dayOfYear ) , 'd' ) ;
}
// FORMATTING
function hFormat ( ) {
return this . hours ( ) % 12 || 12 ;
}
function kFormat ( ) {
return this . hours ( ) || 24 ;
}
addFormatToken ( 'H' , [ 'HH' , 2 ] , 0 , 'hour' ) ;
addFormatToken ( 'h' , [ 'hh' , 2 ] , 0 , hFormat ) ;
addFormatToken ( 'k' , [ 'kk' , 2 ] , 0 , kFormat ) ;
addFormatToken ( 'hmm' , 0 , 0 , function ( ) {
return '' + hFormat . apply ( this ) + zeroFill ( this . minutes ( ) , 2 ) ;
} ) ;
addFormatToken ( 'hmmss' , 0 , 0 , function ( ) {
return '' + hFormat . apply ( this ) + zeroFill ( this . minutes ( ) , 2 ) +
zeroFill ( this . seconds ( ) , 2 ) ;
} ) ;
addFormatToken ( 'Hmm' , 0 , 0 , function ( ) {
return '' + this . hours ( ) + zeroFill ( this . minutes ( ) , 2 ) ;
} ) ;
addFormatToken ( 'Hmmss' , 0 , 0 , function ( ) {
return '' + this . hours ( ) + zeroFill ( this . minutes ( ) , 2 ) +
zeroFill ( this . seconds ( ) , 2 ) ;
} ) ;
function meridiem ( token , lowercase ) {
addFormatToken ( token , 0 , 0 , function ( ) {
return this . localeData ( ) . meridiem ( this . hours ( ) , this . minutes ( ) , lowercase ) ;
} ) ;
}
meridiem ( 'a' , true ) ;
meridiem ( 'A' , false ) ;
// ALIASES
addUnitAlias ( 'hour' , 'h' ) ;
// PARSING
function matchMeridiem ( isStrict , locale ) {
return locale . _meridiemParse ;
}
addRegexToken ( 'a' , matchMeridiem ) ;
addRegexToken ( 'A' , matchMeridiem ) ;
addRegexToken ( 'H' , match1to2 ) ;
addRegexToken ( 'h' , match1to2 ) ;
addRegexToken ( 'HH' , match1to2 , match2 ) ;
addRegexToken ( 'hh' , match1to2 , match2 ) ;
addRegexToken ( 'hmm' , match3to4 ) ;
addRegexToken ( 'hmmss' , match5to6 ) ;
addRegexToken ( 'Hmm' , match3to4 ) ;
addRegexToken ( 'Hmmss' , match5to6 ) ;
addParseToken ( [ 'H' , 'HH' ] , HOUR ) ;
addParseToken ( [ 'a' , 'A' ] , function ( input , array , config ) {
config . _isPm = config . _locale . isPM ( input ) ;
config . _meridiem = input ;
} ) ;
addParseToken ( [ 'h' , 'hh' ] , function ( input , array , config ) {
array [ HOUR ] = toInt ( input ) ;
getParsingFlags ( config ) . bigHour = true ;
} ) ;
addParseToken ( 'hmm' , function ( input , array , config ) {
var pos = input . length - 2 ;
array [ HOUR ] = toInt ( input . substr ( 0 , pos ) ) ;
array [ MINUTE ] = toInt ( input . substr ( pos ) ) ;
getParsingFlags ( config ) . bigHour = true ;
} ) ;
addParseToken ( 'hmmss' , function ( input , array , config ) {
var pos1 = input . length - 4 ;
var pos2 = input . length - 2 ;
array [ HOUR ] = toInt ( input . substr ( 0 , pos1 ) ) ;
array [ MINUTE ] = toInt ( input . substr ( pos1 , 2 ) ) ;
array [ SECOND ] = toInt ( input . substr ( pos2 ) ) ;
getParsingFlags ( config ) . bigHour = true ;
} ) ;
addParseToken ( 'Hmm' , function ( input , array , config ) {
var pos = input . length - 2 ;
array [ HOUR ] = toInt ( input . substr ( 0 , pos ) ) ;
array [ MINUTE ] = toInt ( input . substr ( pos ) ) ;
} ) ;
addParseToken ( 'Hmmss' , function ( input , array , config ) {
var pos1 = input . length - 4 ;
var pos2 = input . length - 2 ;
array [ HOUR ] = toInt ( input . substr ( 0 , pos1 ) ) ;
array [ MINUTE ] = toInt ( input . substr ( pos1 , 2 ) ) ;
array [ SECOND ] = toInt ( input . substr ( pos2 ) ) ;
} ) ;
// LOCALES
function localeIsPM ( input ) {
// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
// Using charAt should be more compatible.
return ( ( input + '' ) . toLowerCase ( ) . charAt ( 0 ) === 'p' ) ;
}
var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i ;
function localeMeridiem ( hours , minutes , isLower ) {
if ( hours > 11 ) {
return isLower ? 'pm' : 'PM' ;
} else {
return isLower ? 'am' : 'AM' ;
}
}
// MOMENTS
// Setting the hour should keep the time, because the user explicitly
// specified which hour he wants. So trying to maintain the same hour (in
// a new timezone) makes sense. Adding/subtracting hours does not follow
// this rule.
var getSetHour = makeGetSet ( 'Hours' , true ) ;
// FORMATTING
addFormatToken ( 'm' , [ 'mm' , 2 ] , 0 , 'minute' ) ;
// ALIASES
addUnitAlias ( 'minute' , 'm' ) ;
// PARSING
addRegexToken ( 'm' , match1to2 ) ;
addRegexToken ( 'mm' , match1to2 , match2 ) ;
addParseToken ( [ 'm' , 'mm' ] , MINUTE ) ;
// MOMENTS
var getSetMinute = makeGetSet ( 'Minutes' , false ) ;
// FORMATTING
addFormatToken ( 's' , [ 'ss' , 2 ] , 0 , 'second' ) ;
// ALIASES
addUnitAlias ( 'second' , 's' ) ;
// PARSING
addRegexToken ( 's' , match1to2 ) ;
addRegexToken ( 'ss' , match1to2 , match2 ) ;
addParseToken ( [ 's' , 'ss' ] , SECOND ) ;
// MOMENTS
var getSetSecond = makeGetSet ( 'Seconds' , false ) ;
// FORMATTING
addFormatToken ( 'S' , 0 , 0 , function ( ) {
return ~ ~ ( this . millisecond ( ) / 100 ) ;
} ) ;
addFormatToken ( 0 , [ 'SS' , 2 ] , 0 , function ( ) {
return ~ ~ ( this . millisecond ( ) / 10 ) ;
} ) ;
addFormatToken ( 0 , [ 'SSS' , 3 ] , 0 , 'millisecond' ) ;
addFormatToken ( 0 , [ 'SSSS' , 4 ] , 0 , function ( ) {
return this . millisecond ( ) * 10 ;
} ) ;
addFormatToken ( 0 , [ 'SSSSS' , 5 ] , 0 , function ( ) {
return this . millisecond ( ) * 100 ;
} ) ;
addFormatToken ( 0 , [ 'SSSSSS' , 6 ] , 0 , function ( ) {
return this . millisecond ( ) * 1000 ;
} ) ;
addFormatToken ( 0 , [ 'SSSSSSS' , 7 ] , 0 , function ( ) {
return this . millisecond ( ) * 10000 ;
} ) ;
addFormatToken ( 0 , [ 'SSSSSSSS' , 8 ] , 0 , function ( ) {
return this . millisecond ( ) * 100000 ;
} ) ;
addFormatToken ( 0 , [ 'SSSSSSSSS' , 9 ] , 0 , function ( ) {
return this . millisecond ( ) * 1000000 ;
} ) ;
// ALIASES
addUnitAlias ( 'millisecond' , 'ms' ) ;
// PARSING
addRegexToken ( 'S' , match1to3 , match1 ) ;
addRegexToken ( 'SS' , match1to3 , match2 ) ;
addRegexToken ( 'SSS' , match1to3 , match3 ) ;
var token ;
for ( token = 'SSSS' ; token . length <= 9 ; token += 'S' ) {
addRegexToken ( token , matchUnsigned ) ;
}
function parseMs ( input , array ) {
array [ MILLISECOND ] = toInt ( ( '0.' + input ) * 1000 ) ;
}
for ( token = 'S' ; token . length <= 9 ; token += 'S' ) {
addParseToken ( token , parseMs ) ;
}
// MOMENTS
var getSetMillisecond = makeGetSet ( 'Milliseconds' , false ) ;
// FORMATTING
addFormatToken ( 'z' , 0 , 0 , 'zoneAbbr' ) ;
addFormatToken ( 'zz' , 0 , 0 , 'zoneName' ) ;
// MOMENTS
function getZoneAbbr ( ) {
return this . _isUTC ? 'UTC' : '' ;
}
function getZoneName ( ) {
return this . _isUTC ? 'Coordinated Universal Time' : '' ;
}
var momentPrototype _ _proto = Moment . prototype ;
momentPrototype _ _proto . add = add _subtract _ _add ;
momentPrototype _ _proto . calendar = moment _calendar _ _calendar ;
momentPrototype _ _proto . clone = clone ;
momentPrototype _ _proto . diff = diff ;
momentPrototype _ _proto . endOf = endOf ;
momentPrototype _ _proto . format = format ;
momentPrototype _ _proto . from = from ;
momentPrototype _ _proto . fromNow = fromNow ;
momentPrototype _ _proto . to = to ;
momentPrototype _ _proto . toNow = toNow ;
momentPrototype _ _proto . get = getSet ;
momentPrototype _ _proto . invalidAt = invalidAt ;
momentPrototype _ _proto . isAfter = isAfter ;
momentPrototype _ _proto . isBefore = isBefore ;
momentPrototype _ _proto . isBetween = isBetween ;
momentPrototype _ _proto . isSame = isSame ;
momentPrototype _ _proto . isSameOrAfter = isSameOrAfter ;
momentPrototype _ _proto . isSameOrBefore = isSameOrBefore ;
momentPrototype _ _proto . isValid = moment _valid _ _isValid ;
momentPrototype _ _proto . lang = lang ;
momentPrototype _ _proto . locale = locale ;
momentPrototype _ _proto . localeData = localeData ;
momentPrototype _ _proto . max = prototypeMax ;
momentPrototype _ _proto . min = prototypeMin ;
momentPrototype _ _proto . parsingFlags = parsingFlags ;
momentPrototype _ _proto . set = getSet ;
momentPrototype _ _proto . startOf = startOf ;
momentPrototype _ _proto . subtract = add _subtract _ _subtract ;
momentPrototype _ _proto . toArray = toArray ;
momentPrototype _ _proto . toObject = toObject ;
momentPrototype _ _proto . toDate = toDate ;
momentPrototype _ _proto . toISOString = moment _format _ _toISOString ;
momentPrototype _ _proto . toJSON = toJSON ;
momentPrototype _ _proto . toString = toString ;
momentPrototype _ _proto . unix = unix ;
momentPrototype _ _proto . valueOf = to _type _ _valueOf ;
momentPrototype _ _proto . creationData = creationData ;
// Year
momentPrototype _ _proto . year = getSetYear ;
momentPrototype _ _proto . isLeapYear = getIsLeapYear ;
// Week Year
momentPrototype _ _proto . weekYear = getSetWeekYear ;
momentPrototype _ _proto . isoWeekYear = getSetISOWeekYear ;
// Quarter
momentPrototype _ _proto . quarter = momentPrototype _ _proto . quarters = getSetQuarter ;
// Month
momentPrototype _ _proto . month = getSetMonth ;
momentPrototype _ _proto . daysInMonth = getDaysInMonth ;
// Week
momentPrototype _ _proto . week = momentPrototype _ _proto . weeks = getSetWeek ;
momentPrototype _ _proto . isoWeek = momentPrototype _ _proto . isoWeeks = getSetISOWeek ;
momentPrototype _ _proto . weeksInYear = getWeeksInYear ;
momentPrototype _ _proto . isoWeeksInYear = getISOWeeksInYear ;
// Day
momentPrototype _ _proto . date = getSetDayOfMonth ;
momentPrototype _ _proto . day = momentPrototype _ _proto . days = getSetDayOfWeek ;
momentPrototype _ _proto . weekday = getSetLocaleDayOfWeek ;
momentPrototype _ _proto . isoWeekday = getSetISODayOfWeek ;
momentPrototype _ _proto . dayOfYear = getSetDayOfYear ;
// Hour
momentPrototype _ _proto . hour = momentPrototype _ _proto . hours = getSetHour ;
// Minute
momentPrototype _ _proto . minute = momentPrototype _ _proto . minutes = getSetMinute ;
// Second
momentPrototype _ _proto . second = momentPrototype _ _proto . seconds = getSetSecond ;
// Millisecond
momentPrototype _ _proto . millisecond = momentPrototype _ _proto . milliseconds = getSetMillisecond ;
// Offset
momentPrototype _ _proto . utcOffset = getSetOffset ;
momentPrototype _ _proto . utc = setOffsetToUTC ;
momentPrototype _ _proto . local = setOffsetToLocal ;
momentPrototype _ _proto . parseZone = setOffsetToParsedOffset ;
momentPrototype _ _proto . hasAlignedHourOffset = hasAlignedHourOffset ;
momentPrototype _ _proto . isDST = isDaylightSavingTime ;
momentPrototype _ _proto . isDSTShifted = isDaylightSavingTimeShifted ;
momentPrototype _ _proto . isLocal = isLocal ;
momentPrototype _ _proto . isUtcOffset = isUtcOffset ;
momentPrototype _ _proto . isUtc = isUtc ;
momentPrototype _ _proto . isUTC = isUtc ;
// Timezone
momentPrototype _ _proto . zoneAbbr = getZoneAbbr ;
momentPrototype _ _proto . zoneName = getZoneName ;
// Deprecations
momentPrototype _ _proto . dates = deprecate ( 'dates accessor is deprecated. Use date instead.' , getSetDayOfMonth ) ;
momentPrototype _ _proto . months = deprecate ( 'months accessor is deprecated. Use month instead' , getSetMonth ) ;
momentPrototype _ _proto . years = deprecate ( 'years accessor is deprecated. Use year instead' , getSetYear ) ;
momentPrototype _ _proto . zone = deprecate ( 'moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779' , getSetZone ) ;
var momentPrototype = momentPrototype _ _proto ;
function moment _ _createUnix ( input ) {
return local _ _createLocal ( input * 1000 ) ;
}
function moment _ _createInZone ( ) {
return local _ _createLocal . apply ( null , arguments ) . parseZone ( ) ;
}
var defaultCalendar = {
sameDay : '[Today at] LT' ,
nextDay : '[Tomorrow at] LT' ,
nextWeek : 'dddd [at] LT' ,
lastDay : '[Yesterday at] LT' ,
lastWeek : '[Last] dddd [at] LT' ,
sameElse : 'L'
} ;
function locale _calendar _ _calendar ( key , mom , now ) {
var output = this . _calendar [ key ] ;
return isFunction ( output ) ? output . call ( mom , now ) : output ;
}
var defaultLongDateFormat = {
LTS : 'h:mm:ss A' ,
LT : 'h:mm A' ,
L : 'MM/DD/YYYY' ,
LL : 'MMMM D, YYYY' ,
LLL : 'MMMM D, YYYY h:mm A' ,
LLLL : 'dddd, MMMM D, YYYY h:mm A'
} ;
function longDateFormat ( key ) {
var format = this . _longDateFormat [ key ] ,
formatUpper = this . _longDateFormat [ key . toUpperCase ( ) ] ;
if ( format || ! formatUpper ) {
return format ;
}
this . _longDateFormat [ key ] = formatUpper . replace ( /MMMM|MM|DD|dddd/g , function ( val ) {
return val . slice ( 1 ) ;
} ) ;
return this . _longDateFormat [ key ] ;
}
var defaultInvalidDate = 'Invalid date' ;
function invalidDate ( ) {
return this . _invalidDate ;
}
var defaultOrdinal = '%d' ;
var defaultOrdinalParse = /\d{1,2}/ ;
function ordinal ( number ) {
return this . _ordinal . replace ( '%d' , number ) ;
}
function preParsePostFormat ( string ) {
return string ;
}
var defaultRelativeTime = {
future : 'in %s' ,
past : '%s ago' ,
s : 'a few seconds' ,
m : 'a minute' ,
mm : '%d minutes' ,
h : 'an hour' ,
hh : '%d hours' ,
d : 'a day' ,
dd : '%d days' ,
M : 'a month' ,
MM : '%d months' ,
y : 'a year' ,
yy : '%d years'
} ;
function relative _ _relativeTime ( number , withoutSuffix , string , isFuture ) {
var output = this . _relativeTime [ string ] ;
return ( isFunction ( output ) ) ?
output ( number , withoutSuffix , string , isFuture ) :
output . replace ( /%d/i , number ) ;
}
function pastFuture ( diff , output ) {
var format = this . _relativeTime [ diff > 0 ? 'future' : 'past' ] ;
return isFunction ( format ) ? format ( output ) : format . replace ( /%s/i , output ) ;
}
var prototype _ _proto = Locale . prototype ;
prototype _ _proto . _calendar = defaultCalendar ;
prototype _ _proto . calendar = locale _calendar _ _calendar ;
prototype _ _proto . _longDateFormat = defaultLongDateFormat ;
prototype _ _proto . longDateFormat = longDateFormat ;
prototype _ _proto . _invalidDate = defaultInvalidDate ;
prototype _ _proto . invalidDate = invalidDate ;
prototype _ _proto . _ordinal = defaultOrdinal ;
prototype _ _proto . ordinal = ordinal ;
prototype _ _proto . _ordinalParse = defaultOrdinalParse ;
prototype _ _proto . preparse = preParsePostFormat ;
prototype _ _proto . postformat = preParsePostFormat ;
prototype _ _proto . _relativeTime = defaultRelativeTime ;
prototype _ _proto . relativeTime = relative _ _relativeTime ;
prototype _ _proto . pastFuture = pastFuture ;
prototype _ _proto . set = locale _set _ _set ;
// Month
prototype _ _proto . months = localeMonths ;
prototype _ _proto . _months = defaultLocaleMonths ;
prototype _ _proto . monthsShort = localeMonthsShort ;
prototype _ _proto . _monthsShort = defaultLocaleMonthsShort ;
prototype _ _proto . monthsParse = localeMonthsParse ;
prototype _ _proto . _monthsRegex = defaultMonthsRegex ;
prototype _ _proto . monthsRegex = monthsRegex ;
prototype _ _proto . _monthsShortRegex = defaultMonthsShortRegex ;
prototype _ _proto . monthsShortRegex = monthsShortRegex ;
// Week
prototype _ _proto . week = localeWeek ;
prototype _ _proto . _week = defaultLocaleWeek ;
prototype _ _proto . firstDayOfYear = localeFirstDayOfYear ;
prototype _ _proto . firstDayOfWeek = localeFirstDayOfWeek ;
// Day of Week
prototype _ _proto . weekdays = localeWeekdays ;
prototype _ _proto . _weekdays = defaultLocaleWeekdays ;
prototype _ _proto . weekdaysMin = localeWeekdaysMin ;
prototype _ _proto . _weekdaysMin = defaultLocaleWeekdaysMin ;
prototype _ _proto . weekdaysShort = localeWeekdaysShort ;
prototype _ _proto . _weekdaysShort = defaultLocaleWeekdaysShort ;
prototype _ _proto . weekdaysParse = localeWeekdaysParse ;
prototype _ _proto . _weekdaysRegex = defaultWeekdaysRegex ;
prototype _ _proto . weekdaysRegex = weekdaysRegex ;
prototype _ _proto . _weekdaysShortRegex = defaultWeekdaysShortRegex ;
prototype _ _proto . weekdaysShortRegex = weekdaysShortRegex ;
prototype _ _proto . _weekdaysMinRegex = defaultWeekdaysMinRegex ;
prototype _ _proto . weekdaysMinRegex = weekdaysMinRegex ;
// Hours
prototype _ _proto . isPM = localeIsPM ;
prototype _ _proto . _meridiemParse = defaultLocaleMeridiemParse ;
prototype _ _proto . meridiem = localeMeridiem ;
function lists _ _get ( format , index , field , setter ) {
var locale = locale _locales _ _getLocale ( ) ;
var utc = create _utc _ _createUTC ( ) . set ( setter , index ) ;
return locale [ field ] ( utc , format ) ;
}
function listMonthsImpl ( format , index , field ) {
if ( typeof format === 'number' ) {
index = format ;
format = undefined ;
}
format = format || '' ;
if ( index != null ) {
return lists _ _get ( format , index , field , 'month' ) ;
}
var i ;
var out = [ ] ;
for ( i = 0 ; i < 12 ; i ++ ) {
out [ i ] = lists _ _get ( format , i , field , 'month' ) ;
}
return out ;
}
// ()
// (5)
// (fmt, 5)
// (fmt)
// (true)
// (true, 5)
// (true, fmt, 5)
// (true, fmt)
function listWeekdaysImpl ( localeSorted , format , index , field ) {
if ( typeof localeSorted === 'boolean' ) {
if ( typeof format === 'number' ) {
index = format ;
format = undefined ;
}
format = format || '' ;
} else {
format = localeSorted ;
index = format ;
localeSorted = false ;
if ( typeof format === 'number' ) {
index = format ;
format = undefined ;
}
format = format || '' ;
}
var locale = locale _locales _ _getLocale ( ) ,
shift = localeSorted ? locale . _week . dow : 0 ;
if ( index != null ) {
return lists _ _get ( format , ( index + shift ) % 7 , field , 'day' ) ;
}
var i ;
var out = [ ] ;
for ( i = 0 ; i < 7 ; i ++ ) {
out [ i ] = lists _ _get ( format , ( i + shift ) % 7 , field , 'day' ) ;
}
return out ;
}
function lists _ _listMonths ( format , index ) {
return listMonthsImpl ( format , index , 'months' ) ;
}
function lists _ _listMonthsShort ( format , index ) {
return listMonthsImpl ( format , index , 'monthsShort' ) ;
}
function lists _ _listWeekdays ( localeSorted , format , index ) {
return listWeekdaysImpl ( localeSorted , format , index , 'weekdays' ) ;
}
function lists _ _listWeekdaysShort ( localeSorted , format , index ) {
return listWeekdaysImpl ( localeSorted , format , index , 'weekdaysShort' ) ;
}
function lists _ _listWeekdaysMin ( localeSorted , format , index ) {
return listWeekdaysImpl ( localeSorted , format , index , 'weekdaysMin' ) ;
}
locale _locales _ _getSetGlobalLocale ( 'en' , {
ordinalParse : /\d{1,2}(th|st|nd|rd)/ ,
ordinal : function ( number ) {
var b = number % 10 ,
output = ( toInt ( number % 100 / 10 ) === 1 ) ? 'th' :
( b === 1 ) ? 'st' :
( b === 2 ) ? 'nd' :
( b === 3 ) ? 'rd' : 'th' ;
return number + output ;
}
} ) ;
// Side effect imports
utils _hooks _ _hooks . lang = deprecate ( 'moment.lang is deprecated. Use moment.locale instead.' , locale _locales _ _getSetGlobalLocale ) ;
utils _hooks _ _hooks . langData = deprecate ( 'moment.langData is deprecated. Use moment.localeData instead.' , locale _locales _ _getLocale ) ;
var mathAbs = Math . abs ;
function duration _abs _ _abs ( ) {
var data = this . _data ;
this . _milliseconds = mathAbs ( this . _milliseconds ) ;
this . _days = mathAbs ( this . _days ) ;
this . _months = mathAbs ( this . _months ) ;
data . milliseconds = mathAbs ( data . milliseconds ) ;
data . seconds = mathAbs ( data . seconds ) ;
data . minutes = mathAbs ( data . minutes ) ;
data . hours = mathAbs ( data . hours ) ;
data . months = mathAbs ( data . months ) ;
data . years = mathAbs ( data . years ) ;
return this ;
}
function duration _add _subtract _ _addSubtract ( duration , input , value , direction ) {
var other = create _ _createDuration ( input , value ) ;
duration . _milliseconds += direction * other . _milliseconds ;
duration . _days += direction * other . _days ;
duration . _months += direction * other . _months ;
return duration . _bubble ( ) ;
}
// supports only 2.0-style add(1, 's') or add(duration)
function duration _add _subtract _ _add ( input , value ) {
return duration _add _subtract _ _addSubtract ( this , input , value , 1 ) ;
}
// supports only 2.0-style subtract(1, 's') or subtract(duration)
function duration _add _subtract _ _subtract ( input , value ) {
return duration _add _subtract _ _addSubtract ( this , input , value , - 1 ) ;
}
function absCeil ( number ) {
if ( number < 0 ) {
return Math . floor ( number ) ;
} else {
return Math . ceil ( number ) ;
}
}
function bubble ( ) {
var milliseconds = this . _milliseconds ;
var days = this . _days ;
var months = this . _months ;
var data = this . _data ;
var seconds , minutes , hours , years , monthsFromDays ;
// if we have a mix of positive and negative values, bubble down first
// check: https://github.com/moment/moment/issues/2166
if ( ! ( ( milliseconds >= 0 && days >= 0 && months >= 0 ) ||
( milliseconds <= 0 && days <= 0 && months <= 0 ) ) ) {
milliseconds += absCeil ( monthsToDays ( months ) + days ) * 864e5 ;
days = 0 ;
months = 0 ;
}
// The following code bubbles up values, see the tests for
// examples of what that means.
data . milliseconds = milliseconds % 1000 ;
seconds = absFloor ( milliseconds / 1000 ) ;
data . seconds = seconds % 60 ;
minutes = absFloor ( seconds / 60 ) ;
data . minutes = minutes % 60 ;
hours = absFloor ( minutes / 60 ) ;
data . hours = hours % 24 ;
days += absFloor ( hours / 24 ) ;
// convert days to months
monthsFromDays = absFloor ( daysToMonths ( days ) ) ;
months += monthsFromDays ;
days -= absCeil ( monthsToDays ( monthsFromDays ) ) ;
// 12 months -> 1 year
years = absFloor ( months / 12 ) ;
months %= 12 ;
data . days = days ;
data . months = months ;
data . years = years ;
return this ;
}
function daysToMonths ( days ) {
// 400 years have 146097 days (taking into account leap year rules)
// 400 years have 12 months === 4800
return days * 4800 / 146097 ;
}
function monthsToDays ( months ) {
// the reverse of daysToMonths
return months * 146097 / 4800 ;
}
function as ( units ) {
var days ;
var months ;
var milliseconds = this . _milliseconds ;
units = normalizeUnits ( units ) ;
if ( units === 'month' || units === 'year' ) {
days = this . _days + milliseconds / 864e5 ;
months = this . _months + daysToMonths ( days ) ;
return units === 'month' ? months : months / 12 ;
} else {
// handle milliseconds separately because of floating point math errors (issue #1867)
days = this . _days + Math . round ( monthsToDays ( this . _months ) ) ;
switch ( units ) {
case 'week' : return days / 7 + milliseconds / 6048e5 ;
case 'day' : return days + milliseconds / 864e5 ;
case 'hour' : return days * 24 + milliseconds / 36e5 ;
case 'minute' : return days * 1440 + milliseconds / 6e4 ;
case 'second' : return days * 86400 + milliseconds / 1000 ;
// Math.floor prevents floating point math errors here
case 'millisecond' : return Math . floor ( days * 864e5 ) + milliseconds ;
default : throw new Error ( 'Unknown unit ' + units ) ;
}
}
}
// TODO: Use this.as('ms')?
function duration _as _ _valueOf ( ) {
return (
this . _milliseconds +
this . _days * 864e5 +
( this . _months % 12 ) * 2592e6 +
toInt ( this . _months / 12 ) * 31536e6
) ;
}
function makeAs ( alias ) {
return function ( ) {
return this . as ( alias ) ;
} ;
}
var asMilliseconds = makeAs ( 'ms' ) ;
var asSeconds = makeAs ( 's' ) ;
var asMinutes = makeAs ( 'm' ) ;
var asHours = makeAs ( 'h' ) ;
var asDays = makeAs ( 'd' ) ;
var asWeeks = makeAs ( 'w' ) ;
var asMonths = makeAs ( 'M' ) ;
var asYears = makeAs ( 'y' ) ;
function duration _get _ _get ( units ) {
units = normalizeUnits ( units ) ;
return this [ units + 's' ] ( ) ;
}
function makeGetter ( name ) {
return function ( ) {
return this . _data [ name ] ;
} ;
}
var milliseconds = makeGetter ( 'milliseconds' ) ;
var seconds = makeGetter ( 'seconds' ) ;
var minutes = makeGetter ( 'minutes' ) ;
var hours = makeGetter ( 'hours' ) ;
var days = makeGetter ( 'days' ) ;
var months = makeGetter ( 'months' ) ;
var years = makeGetter ( 'years' ) ;
function weeks ( ) {
return absFloor ( this . days ( ) / 7 ) ;
}
var round = Math . round ;
var thresholds = {
s : 45 , // seconds to minute
m : 45 , // minutes to hour
h : 22 , // hours to day
d : 26 , // days to month
M : 11 // months to year
} ;
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
function substituteTimeAgo ( string , number , withoutSuffix , isFuture , locale ) {
return locale . relativeTime ( number || 1 , ! ! withoutSuffix , string , isFuture ) ;
}
function duration _humanize _ _relativeTime ( posNegDuration , withoutSuffix , locale ) {
var duration = create _ _createDuration ( posNegDuration ) . abs ( ) ;
var seconds = round ( duration . as ( 's' ) ) ;
var minutes = round ( duration . as ( 'm' ) ) ;
var hours = round ( duration . as ( 'h' ) ) ;
var days = round ( duration . as ( 'd' ) ) ;
var months = round ( duration . as ( 'M' ) ) ;
var years = round ( duration . as ( 'y' ) ) ;
var a = seconds < thresholds . s && [ 's' , seconds ] ||
minutes <= 1 && [ 'm' ] ||
minutes < thresholds . m && [ 'mm' , minutes ] ||
hours <= 1 && [ 'h' ] ||
hours < thresholds . h && [ 'hh' , hours ] ||
days <= 1 && [ 'd' ] ||
days < thresholds . d && [ 'dd' , days ] ||
months <= 1 && [ 'M' ] ||
months < thresholds . M && [ 'MM' , months ] ||
years <= 1 && [ 'y' ] || [ 'yy' , years ] ;
a [ 2 ] = withoutSuffix ;
a [ 3 ] = + posNegDuration > 0 ;
a [ 4 ] = locale ;
return substituteTimeAgo . apply ( null , a ) ;
}
// This function allows you to set a threshold for relative time strings
function duration _humanize _ _getSetRelativeTimeThreshold ( threshold , limit ) {
if ( thresholds [ threshold ] === undefined ) {
return false ;
}
if ( limit === undefined ) {
return thresholds [ threshold ] ;
}
thresholds [ threshold ] = limit ;
return true ;
}
function humanize ( withSuffix ) {
var locale = this . localeData ( ) ;
var output = duration _humanize _ _relativeTime ( this , ! withSuffix , locale ) ;
if ( withSuffix ) {
output = locale . pastFuture ( + this , output ) ;
}
return locale . postformat ( output ) ;
}
var iso _string _ _abs = Math . abs ;
function iso _string _ _toISOString ( ) {
// for ISO strings we do not use the normal bubbling rules:
// * milliseconds bubble up until they become hours
// * days do not bubble at all
// * months bubble up until they become years
// This is because there is no context-free conversion between hours and days
// (think of clock changes)
// and also not between days and months (28-31 days per month)
var seconds = iso _string _ _abs ( this . _milliseconds ) / 1000 ;
var days = iso _string _ _abs ( this . _days ) ;
var months = iso _string _ _abs ( this . _months ) ;
var minutes , hours , years ;
// 3600 seconds -> 60 minutes -> 1 hour
minutes = absFloor ( seconds / 60 ) ;
hours = absFloor ( minutes / 60 ) ;
seconds %= 60 ;
minutes %= 60 ;
// 12 months -> 1 year
years = absFloor ( months / 12 ) ;
months %= 12 ;
// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
var Y = years ;
var M = months ;
var D = days ;
var h = hours ;
var m = minutes ;
var s = seconds ;
var total = this . asSeconds ( ) ;
if ( ! total ) {
// this is the same as C#'s (Noda) and python (isodate)...
// but not other JS (goog.date)
return 'P0D' ;
}
return ( total < 0 ? '-' : '' ) +
'P' +
( Y ? Y + 'Y' : '' ) +
( M ? M + 'M' : '' ) +
( D ? D + 'D' : '' ) +
( ( h || m || s ) ? 'T' : '' ) +
( h ? h + 'H' : '' ) +
( m ? m + 'M' : '' ) +
( s ? s + 'S' : '' ) ;
}
var duration _prototype _ _proto = Duration . prototype ;
duration _prototype _ _proto . abs = duration _abs _ _abs ;
duration _prototype _ _proto . add = duration _add _subtract _ _add ;
duration _prototype _ _proto . subtract = duration _add _subtract _ _subtract ;
duration _prototype _ _proto . as = as ;
duration _prototype _ _proto . asMilliseconds = asMilliseconds ;
duration _prototype _ _proto . asSeconds = asSeconds ;
duration _prototype _ _proto . asMinutes = asMinutes ;
duration _prototype _ _proto . asHours = asHours ;
duration _prototype _ _proto . asDays = asDays ;
duration _prototype _ _proto . asWeeks = asWeeks ;
duration _prototype _ _proto . asMonths = asMonths ;
duration _prototype _ _proto . asYears = asYears ;
duration _prototype _ _proto . valueOf = duration _as _ _valueOf ;
duration _prototype _ _proto . _bubble = bubble ;
duration _prototype _ _proto . get = duration _get _ _get ;
duration _prototype _ _proto . milliseconds = milliseconds ;
duration _prototype _ _proto . seconds = seconds ;
duration _prototype _ _proto . minutes = minutes ;
duration _prototype _ _proto . hours = hours ;
duration _prototype _ _proto . days = days ;
duration _prototype _ _proto . weeks = weeks ;
duration _prototype _ _proto . months = months ;
duration _prototype _ _proto . years = years ;
duration _prototype _ _proto . humanize = humanize ;
duration _prototype _ _proto . toISOString = iso _string _ _toISOString ;
duration _prototype _ _proto . toString = iso _string _ _toISOString ;
duration _prototype _ _proto . toJSON = iso _string _ _toISOString ;
duration _prototype _ _proto . locale = locale ;
duration _prototype _ _proto . localeData = localeData ;
// Deprecations
duration _prototype _ _proto . toIsoString = deprecate ( 'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)' , iso _string _ _toISOString ) ;
duration _prototype _ _proto . lang = lang ;
// Side effect imports
// FORMATTING
addFormatToken ( 'X' , 0 , 0 , 'unix' ) ;
addFormatToken ( 'x' , 0 , 0 , 'valueOf' ) ;
// PARSING
addRegexToken ( 'x' , matchSigned ) ;
addRegexToken ( 'X' , matchTimestamp ) ;
addParseToken ( 'X' , function ( input , array , config ) {
config . _d = new Date ( parseFloat ( input , 10 ) * 1000 ) ;
} ) ;
addParseToken ( 'x' , function ( input , array , config ) {
config . _d = new Date ( toInt ( input ) ) ;
} ) ;
// Side effect imports
utils _hooks _ _hooks . version = '2.13.0' ;
setHookCallback ( local _ _createLocal ) ;
utils _hooks _ _hooks . fn = momentPrototype ;
utils _hooks _ _hooks . min = min ;
utils _hooks _ _hooks . max = max ;
utils _hooks _ _hooks . now = now ;
utils _hooks _ _hooks . utc = create _utc _ _createUTC ;
utils _hooks _ _hooks . unix = moment _ _createUnix ;
utils _hooks _ _hooks . months = lists _ _listMonths ;
utils _hooks _ _hooks . isDate = isDate ;
utils _hooks _ _hooks . locale = locale _locales _ _getSetGlobalLocale ;
utils _hooks _ _hooks . invalid = valid _ _createInvalid ;
utils _hooks _ _hooks . duration = create _ _createDuration ;
utils _hooks _ _hooks . isMoment = isMoment ;
utils _hooks _ _hooks . weekdays = lists _ _listWeekdays ;
utils _hooks _ _hooks . parseZone = moment _ _createInZone ;
utils _hooks _ _hooks . localeData = locale _locales _ _getLocale ;
utils _hooks _ _hooks . isDuration = isDuration ;
utils _hooks _ _hooks . monthsShort = lists _ _listMonthsShort ;
utils _hooks _ _hooks . weekdaysMin = lists _ _listWeekdaysMin ;
utils _hooks _ _hooks . defineLocale = defineLocale ;
utils _hooks _ _hooks . updateLocale = updateLocale ;
utils _hooks _ _hooks . locales = locale _locales _ _listLocales ;
utils _hooks _ _hooks . weekdaysShort = lists _ _listWeekdaysShort ;
utils _hooks _ _hooks . normalizeUnits = normalizeUnits ;
utils _hooks _ _hooks . relativeTimeThreshold = duration _humanize _ _getSetRelativeTimeThreshold ;
utils _hooks _ _hooks . prototype = momentPrototype ;
var _moment = utils _hooks _ _hooks ;
return _moment ;
} ) ) ;
} , { } ] , 7 : [ function ( require , module , exports ) {
var Chart = require ( './core/core.js' ) ( ) ;
require ( './core/core.helpers' ) ( Chart ) ;
require ( './core/core.element' ) ( Chart ) ;
require ( './core/core.animation' ) ( Chart ) ;
require ( './core/core.controller' ) ( Chart ) ;
require ( './core/core.datasetController' ) ( Chart ) ;
require ( './core/core.layoutService' ) ( Chart ) ;
require ( './core/core.legend' ) ( Chart ) ;
require ( './core/core.plugin.js' ) ( Chart ) ;
require ( './core/core.scale' ) ( Chart ) ;
require ( './core/core.scaleService' ) ( Chart ) ;
require ( './core/core.title' ) ( Chart ) ;
require ( './core/core.tooltip' ) ( Chart ) ;
require ( './controllers/controller.bar' ) ( Chart ) ;
require ( './controllers/controller.bubble' ) ( Chart ) ;
require ( './controllers/controller.doughnut' ) ( Chart ) ;
require ( './controllers/controller.line' ) ( Chart ) ;
require ( './controllers/controller.polarArea' ) ( Chart ) ;
require ( './controllers/controller.radar' ) ( Chart ) ;
require ( './scales/scale.category' ) ( Chart ) ;
require ( './scales/scale.linear' ) ( Chart ) ;
require ( './scales/scale.logarithmic' ) ( Chart ) ;
require ( './scales/scale.radialLinear' ) ( Chart ) ;
require ( './scales/scale.time' ) ( Chart ) ;
require ( './elements/element.arc' ) ( Chart ) ;
require ( './elements/element.line' ) ( Chart ) ;
require ( './elements/element.point' ) ( Chart ) ;
require ( './elements/element.rectangle' ) ( Chart ) ;
require ( './charts/Chart.Bar' ) ( Chart ) ;
require ( './charts/Chart.Bubble' ) ( Chart ) ;
require ( './charts/Chart.Doughnut' ) ( Chart ) ;
require ( './charts/Chart.Line' ) ( Chart ) ;
require ( './charts/Chart.PolarArea' ) ( Chart ) ;
require ( './charts/Chart.Radar' ) ( Chart ) ;
require ( './charts/Chart.Scatter' ) ( Chart ) ;
window . Chart = module . exports = Chart ;
} , { "./charts/Chart.Bar" : 8 , "./charts/Chart.Bubble" : 9 , "./charts/Chart.Doughnut" : 10 , "./charts/Chart.Line" : 11 , "./charts/Chart.PolarArea" : 12 , "./charts/Chart.Radar" : 13 , "./charts/Chart.Scatter" : 14 , "./controllers/controller.bar" : 15 , "./controllers/controller.bubble" : 16 , "./controllers/controller.doughnut" : 17 , "./controllers/controller.line" : 18 , "./controllers/controller.polarArea" : 19 , "./controllers/controller.radar" : 20 , "./core/core.animation" : 21 , "./core/core.controller" : 22 , "./core/core.datasetController" : 23 , "./core/core.element" : 24 , "./core/core.helpers" : 25 , "./core/core.js" : 26 , "./core/core.layoutService" : 27 , "./core/core.legend" : 28 , "./core/core.plugin.js" : 29 , "./core/core.scale" : 30 , "./core/core.scaleService" : 31 , "./core/core.title" : 32 , "./core/core.tooltip" : 33 , "./elements/element.arc" : 34 , "./elements/element.line" : 35 , "./elements/element.point" : 36 , "./elements/element.rectangle" : 37 , "./scales/scale.category" : 38 , "./scales/scale.linear" : 39 , "./scales/scale.logarithmic" : 40 , "./scales/scale.radialLinear" : 41 , "./scales/scale.time" : 42 } ] , 8 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
Chart . Bar = function ( context , config ) {
config . type = 'bar' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 9 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
Chart . Bubble = function ( context , config ) {
config . type = 'bubble' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 10 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
Chart . Doughnut = function ( context , config ) {
config . type = 'doughnut' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 11 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
Chart . Line = function ( context , config ) {
config . type = 'line' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 12 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
Chart . PolarArea = function ( context , config ) {
config . type = 'polarArea' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 13 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var defaultConfig = {
aspectRatio : 1
} ;
Chart . Radar = function ( context , config ) {
config . options = helpers . configMerge ( defaultConfig , config . options ) ;
config . type = 'radar' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 14 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var defaultConfig = {
hover : {
mode : 'single'
} ,
scales : {
xAxes : [ {
type : "linear" , // scatter should not use a category axis
position : "bottom" ,
id : "x-axis-1" // need an ID so datasets can reference the scale
} ] ,
yAxes : [ {
type : "linear" ,
position : "left" ,
id : "y-axis-1"
} ]
} ,
tooltips : {
callbacks : {
title : function ( tooltipItems , data ) {
// Title doesn't make sense for scatter since we format the data as a point
return '' ;
} ,
label : function ( tooltipItem , data ) {
return '(' + tooltipItem . xLabel + ', ' + tooltipItem . yLabel + ')' ;
}
}
}
} ;
// Register the default config for this type
Chart . defaults . scatter = defaultConfig ;
// Scatter charts use line controllers
Chart . controllers . scatter = Chart . controllers . line ;
Chart . Scatter = function ( context , config ) {
config . type = 'scatter' ;
return new Chart ( context , config ) ;
} ;
} ;
} , { } ] , 15 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . bar = {
hover : {
mode : "label"
} ,
scales : {
xAxes : [ {
type : "category" ,
// Specific to Bar Controller
categoryPercentage : 0.8 ,
barPercentage : 0.9 ,
// grid line settings
gridLines : {
offsetGridLines : true
}
} ] ,
yAxes : [ {
type : "linear"
} ]
}
} ;
Chart . controllers . bar = Chart . DatasetController . extend ( {
initialize : function ( chart , datasetIndex ) {
Chart . DatasetController . prototype . initialize . call ( this , chart , datasetIndex ) ;
// Use this to indicate that this is a bar dataset.
this . getMeta ( ) . bar = true ;
} ,
// Get the number of datasets that display bars. We use this to correctly calculate the bar width
getBarCount : function getBarCount ( ) {
var barCount = 0 ;
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
var meta = this . chart . getDatasetMeta ( datasetIndex ) ;
if ( meta . bar && this . chart . isDatasetVisible ( datasetIndex ) ) {
++ barCount ;
}
} , this ) ;
return barCount ;
} ,
addElements : function ( ) {
var meta = this . getMeta ( ) ;
helpers . each ( this . getDataset ( ) . data , function ( value , index ) {
meta . data [ index ] = meta . data [ index ] || new Chart . elements . Rectangle ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
} , this ) ;
} ,
addElementAndReset : function ( index ) {
var rectangle = new Chart . elements . Rectangle ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
var numBars = this . getBarCount ( ) ;
// Add to the points array and reset it
this . getMeta ( ) . data . splice ( index , 0 , rectangle ) ;
this . updateElement ( rectangle , index , true , numBars ) ;
} ,
update : function update ( reset ) {
var numBars = this . getBarCount ( ) ;
helpers . each ( this . getMeta ( ) . data , function ( rectangle , index ) {
this . updateElement ( rectangle , index , reset , numBars ) ;
} , this ) ;
} ,
updateElement : function updateElement ( rectangle , index , reset , numBars ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var yScalePoint ;
if ( yScale . min < 0 && yScale . max < 0 ) {
// all less than 0. use the top
yScalePoint = yScale . getPixelForValue ( yScale . max ) ;
} else if ( yScale . min > 0 && yScale . max > 0 ) {
yScalePoint = yScale . getPixelForValue ( yScale . min ) ;
} else {
yScalePoint = yScale . getPixelForValue ( 0 ) ;
}
helpers . extend ( rectangle , {
// Utility
_chart : this . chart . chart ,
_xScale : xScale ,
_yScale : yScale ,
_datasetIndex : this . index ,
_index : index ,
// Desired view properties
_model : {
x : this . calculateBarX ( index , this . index ) ,
y : reset ? yScalePoint : this . calculateBarY ( index , this . index ) ,
// Tooltip
label : this . chart . data . labels [ index ] ,
datasetLabel : this . getDataset ( ) . label ,
// Appearance
base : reset ? yScalePoint : this . calculateBarBase ( this . index , index ) ,
width : this . calculateBarWidth ( numBars ) ,
backgroundColor : rectangle . custom && rectangle . custom . backgroundColor ? rectangle . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . rectangle . backgroundColor ) ,
borderSkipped : rectangle . custom && rectangle . custom . borderSkipped ? rectangle . custom . borderSkipped : this . chart . options . elements . rectangle . borderSkipped ,
borderColor : rectangle . custom && rectangle . custom . borderColor ? rectangle . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . rectangle . borderColor ) ,
borderWidth : rectangle . custom && rectangle . custom . borderWidth ? rectangle . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . rectangle . borderWidth )
}
} ) ;
rectangle . pivot ( ) ;
} ,
calculateBarBase : function ( datasetIndex , index ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var base = 0 ;
if ( yScale . options . stacked ) {
var value = this . chart . data . datasets [ datasetIndex ] . data [ index ] ;
if ( value < 0 ) {
for ( var i = 0 ; i < datasetIndex ; i ++ ) {
var negDS = this . chart . data . datasets [ i ] ;
var negDSMeta = this . chart . getDatasetMeta ( i ) ;
if ( negDSMeta . bar && negDSMeta . yAxisID === yScale . id && this . chart . isDatasetVisible ( i ) ) {
base += negDS . data [ index ] < 0 ? negDS . data [ index ] : 0 ;
}
}
} else {
for ( var j = 0 ; j < datasetIndex ; j ++ ) {
var posDS = this . chart . data . datasets [ j ] ;
var posDSMeta = this . chart . getDatasetMeta ( j ) ;
if ( posDSMeta . bar && posDSMeta . yAxisID === yScale . id && this . chart . isDatasetVisible ( j ) ) {
base += posDS . data [ index ] > 0 ? posDS . data [ index ] : 0 ;
}
}
}
return yScale . getPixelForValue ( base ) ;
}
base = yScale . getPixelForValue ( yScale . min ) ;
if ( yScale . beginAtZero || ( ( yScale . min <= 0 && yScale . max >= 0 ) || ( yScale . min >= 0 && yScale . max <= 0 ) ) ) {
base = yScale . getPixelForValue ( 0 , 0 ) ;
//base += yScale.options.gridLines.lineWidth;
} else if ( yScale . min < 0 && yScale . max < 0 ) {
// All values are negative. Use the top as the base
base = yScale . getPixelForValue ( yScale . max ) ;
}
return base ;
} ,
getRuler : function ( ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var datasetCount = this . getBarCount ( ) ;
var tickWidth = ( function ( ) {
var min = xScale . getPixelForTick ( 1 ) - xScale . getPixelForTick ( 0 ) ;
for ( var i = 2 ; i < xScale . ticks . length ; i ++ ) {
min = Math . min ( xScale . getPixelForTick ( i ) - xScale . getPixelForTick ( i - 1 ) , min ) ;
}
return min ;
} ) . call ( this ) ;
var categoryWidth = tickWidth * xScale . options . categoryPercentage ;
var categorySpacing = ( tickWidth - ( tickWidth * xScale . options . categoryPercentage ) ) / 2 ;
var fullBarWidth = categoryWidth / datasetCount ;
if ( xScale . ticks . length !== this . chart . data . labels . length ) {
var perc = xScale . ticks . length / this . chart . data . labels . length ;
fullBarWidth = fullBarWidth * perc ;
}
var barWidth = fullBarWidth * xScale . options . barPercentage ;
var barSpacing = fullBarWidth - ( fullBarWidth * xScale . options . barPercentage ) ;
return {
datasetCount : datasetCount ,
tickWidth : tickWidth ,
categoryWidth : categoryWidth ,
categorySpacing : categorySpacing ,
fullBarWidth : fullBarWidth ,
barWidth : barWidth ,
barSpacing : barSpacing
} ;
} ,
calculateBarWidth : function ( ) {
var xScale = this . getScaleForId ( this . getMeta ( ) . xAxisID ) ;
var ruler = this . getRuler ( ) ;
return xScale . options . stacked ? ruler . categoryWidth : ruler . barWidth ;
} ,
// Get bar index from the given dataset index accounting for the fact that not all bars are visible
getBarIndex : function ( datasetIndex ) {
var barIndex = 0 ;
var meta , j ;
for ( j = 0 ; j < datasetIndex ; ++ j ) {
meta = this . chart . getDatasetMeta ( j ) ;
if ( meta . bar && this . chart . isDatasetVisible ( j ) ) {
++ barIndex ;
}
}
return barIndex ;
} ,
calculateBarX : function ( index , datasetIndex ) {
var meta = this . getMeta ( ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var barIndex = this . getBarIndex ( datasetIndex ) ;
var ruler = this . getRuler ( ) ;
var leftTick = xScale . getPixelForValue ( null , index , datasetIndex , this . chart . isCombo ) ;
leftTick -= this . chart . isCombo ? ( ruler . tickWidth / 2 ) : 0 ;
if ( xScale . options . stacked ) {
return leftTick + ( ruler . categoryWidth / 2 ) + ruler . categorySpacing ;
}
return leftTick +
( ruler . barWidth / 2 ) +
ruler . categorySpacing +
( ruler . barWidth * barIndex ) +
( ruler . barSpacing / 2 ) +
( ruler . barSpacing * barIndex ) ;
} ,
calculateBarY : function ( index , datasetIndex ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var value = this . getDataset ( ) . data [ index ] ;
if ( yScale . options . stacked ) {
var sumPos = 0 ,
sumNeg = 0 ;
for ( var i = 0 ; i < datasetIndex ; i ++ ) {
var ds = this . chart . data . datasets [ i ] ;
var dsMeta = this . chart . getDatasetMeta ( i ) ;
if ( dsMeta . bar && dsMeta . yAxisID === yScale . id && this . chart . isDatasetVisible ( i ) ) {
if ( ds . data [ index ] < 0 ) {
sumNeg += ds . data [ index ] || 0 ;
} else {
sumPos += ds . data [ index ] || 0 ;
}
}
}
if ( value < 0 ) {
return yScale . getPixelForValue ( sumNeg + value ) ;
} else {
return yScale . getPixelForValue ( sumPos + value ) ;
}
}
return yScale . getPixelForValue ( value ) ;
} ,
draw : function ( ease ) {
var easingDecimal = ease || 1 ;
helpers . each ( this . getMeta ( ) . data , function ( rectangle , index ) {
var d = this . getDataset ( ) . data [ index ] ;
if ( d !== null && d !== undefined && ! isNaN ( d ) ) {
rectangle . transition ( easingDecimal ) . draw ( ) ;
}
} , this ) ;
} ,
setHoverStyle : function ( rectangle ) {
var dataset = this . chart . data . datasets [ rectangle . _datasetIndex ] ;
var index = rectangle . _index ;
rectangle . _model . backgroundColor = rectangle . custom && rectangle . custom . hoverBackgroundColor ? rectangle . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBackgroundColor , index , helpers . getHoverColor ( rectangle . _model . backgroundColor ) ) ;
rectangle . _model . borderColor = rectangle . custom && rectangle . custom . hoverBorderColor ? rectangle . custom . hoverBorderColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderColor , index , helpers . getHoverColor ( rectangle . _model . borderColor ) ) ;
rectangle . _model . borderWidth = rectangle . custom && rectangle . custom . hoverBorderWidth ? rectangle . custom . hoverBorderWidth : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderWidth , index , rectangle . _model . borderWidth ) ;
} ,
removeHoverStyle : function ( rectangle ) {
var dataset = this . chart . data . datasets [ rectangle . _datasetIndex ] ;
var index = rectangle . _index ;
rectangle . _model . backgroundColor = rectangle . custom && rectangle . custom . backgroundColor ? rectangle . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . rectangle . backgroundColor ) ;
rectangle . _model . borderColor = rectangle . custom && rectangle . custom . borderColor ? rectangle . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . rectangle . borderColor ) ;
rectangle . _model . borderWidth = rectangle . custom && rectangle . custom . borderWidth ? rectangle . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . rectangle . borderWidth ) ;
}
} ) ;
// including horizontalBar in the bar file, instead of a file of its own
// it extends bar (like pie extends doughnut)
Chart . defaults . horizontalBar = {
hover : {
mode : "label"
} ,
scales : {
xAxes : [ {
type : "linear" ,
position : "bottom"
} ] ,
yAxes : [ {
position : "left" ,
type : "category" ,
// Specific to Horizontal Bar Controller
categoryPercentage : 0.8 ,
barPercentage : 0.9 ,
// grid line settings
gridLines : {
offsetGridLines : true
}
} ]
} ,
} ;
Chart . controllers . horizontalBar = Chart . controllers . bar . extend ( {
updateElement : function updateElement ( rectangle , index , reset , numBars ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScalePoint ;
if ( xScale . min < 0 && xScale . max < 0 ) {
// all less than 0. use the right
xScalePoint = xScale . getPixelForValue ( xScale . max ) ;
} else if ( xScale . min > 0 && xScale . max > 0 ) {
xScalePoint = xScale . getPixelForValue ( xScale . min ) ;
} else {
xScalePoint = xScale . getPixelForValue ( 0 ) ;
}
helpers . extend ( rectangle , {
// Utility
_chart : this . chart . chart ,
_xScale : xScale ,
_yScale : yScale ,
_datasetIndex : this . index ,
_index : index ,
// Desired view properties
_model : {
x : reset ? xScalePoint : this . calculateBarX ( index , this . index ) ,
y : this . calculateBarY ( index , this . index ) ,
// Tooltip
label : this . chart . data . labels [ index ] ,
datasetLabel : this . getDataset ( ) . label ,
// Appearance
base : reset ? xScalePoint : this . calculateBarBase ( this . index , index ) ,
height : this . calculateBarHeight ( numBars ) ,
backgroundColor : rectangle . custom && rectangle . custom . backgroundColor ? rectangle . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . rectangle . backgroundColor ) ,
borderSkipped : rectangle . custom && rectangle . custom . borderSkipped ? rectangle . custom . borderSkipped : this . chart . options . elements . rectangle . borderSkipped ,
borderColor : rectangle . custom && rectangle . custom . borderColor ? rectangle . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . rectangle . borderColor ) ,
borderWidth : rectangle . custom && rectangle . custom . borderWidth ? rectangle . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . rectangle . borderWidth )
} ,
draw : function ( ) {
var ctx = this . _chart . ctx ;
var vm = this . _view ;
var halfHeight = vm . height / 2 ,
topY = vm . y - halfHeight ,
bottomY = vm . y + halfHeight ,
right = vm . base - ( vm . base - vm . x ) ,
halfStroke = vm . borderWidth / 2 ;
// Canvas doesn't allow us to stroke inside the width so we can
// adjust the sizes to fit if we're setting a stroke on the line
if ( vm . borderWidth ) {
topY += halfStroke ;
bottomY -= halfStroke ;
right += halfStroke ;
}
ctx . beginPath ( ) ;
ctx . fillStyle = vm . backgroundColor ;
ctx . strokeStyle = vm . borderColor ;
ctx . lineWidth = vm . borderWidth ;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
var corners = [
[ vm . base , bottomY ] ,
[ vm . base , topY ] ,
[ right , topY ] ,
[ right , bottomY ]
] ;
// Find first (starting) corner with fallback to 'bottom'
var borders = [ 'bottom' , 'left' , 'top' , 'right' ] ;
var startCorner = borders . indexOf ( vm . borderSkipped , 0 ) ;
if ( startCorner === - 1 )
startCorner = 0 ;
function cornerAt ( index ) {
return corners [ ( startCorner + index ) % 4 ] ;
}
// Draw rectangle from 'startCorner'
ctx . moveTo . apply ( ctx , cornerAt ( 0 ) ) ;
for ( var i = 1 ; i < 4 ; i ++ )
ctx . lineTo . apply ( ctx , cornerAt ( i ) ) ;
ctx . fill ( ) ;
if ( vm . borderWidth ) {
ctx . stroke ( ) ;
}
} ,
inRange : function ( mouseX , mouseY ) {
var vm = this . _view ;
var inRange = false ;
if ( vm ) {
if ( vm . x < vm . base ) {
inRange = ( mouseY >= vm . y - vm . height / 2 && mouseY <= vm . y + vm . height / 2 ) && ( mouseX >= vm . x && mouseX <= vm . base ) ;
} else {
inRange = ( mouseY >= vm . y - vm . height / 2 && mouseY <= vm . y + vm . height / 2 ) && ( mouseX >= vm . base && mouseX <= vm . x ) ;
}
}
return inRange ;
}
} ) ;
rectangle . pivot ( ) ;
} ,
calculateBarBase : function ( datasetIndex , index ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var base = 0 ;
if ( xScale . options . stacked ) {
var value = this . chart . data . datasets [ datasetIndex ] . data [ index ] ;
if ( value < 0 ) {
for ( var i = 0 ; i < datasetIndex ; i ++ ) {
var negDS = this . chart . data . datasets [ i ] ;
var negDSMeta = this . chart . getDatasetMeta ( i ) ;
if ( negDSMeta . bar && negDSMeta . xAxisID === xScale . id && this . chart . isDatasetVisible ( i ) ) {
base += negDS . data [ index ] < 0 ? negDS . data [ index ] : 0 ;
}
}
} else {
for ( var j = 0 ; j < datasetIndex ; j ++ ) {
var posDS = this . chart . data . datasets [ j ] ;
var posDSMeta = this . chart . getDatasetMeta ( j ) ;
if ( posDSMeta . bar && posDSMeta . xAxisID === xScale . id && this . chart . isDatasetVisible ( j ) ) {
base += posDS . data [ index ] > 0 ? posDS . data [ index ] : 0 ;
}
}
}
return xScale . getPixelForValue ( base ) ;
}
base = xScale . getPixelForValue ( xScale . min ) ;
if ( xScale . beginAtZero || ( ( xScale . min <= 0 && xScale . max >= 0 ) || ( xScale . min >= 0 && xScale . max <= 0 ) ) ) {
base = xScale . getPixelForValue ( 0 , 0 ) ;
} else if ( xScale . min < 0 && xScale . max < 0 ) {
// All values are negative. Use the right as the base
base = xScale . getPixelForValue ( xScale . max ) ;
}
return base ;
} ,
getRuler : function ( ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var datasetCount = this . getBarCount ( ) ;
var tickHeight = ( function ( ) {
var min = yScale . getPixelForTick ( 1 ) - yScale . getPixelForTick ( 0 ) ;
for ( var i = 2 ; i < this . getDataset ( ) . data . length ; i ++ ) {
min = Math . min ( yScale . getPixelForTick ( i ) - yScale . getPixelForTick ( i - 1 ) , min ) ;
}
return min ;
} ) . call ( this ) ;
var categoryHeight = tickHeight * yScale . options . categoryPercentage ;
var categorySpacing = ( tickHeight - ( tickHeight * yScale . options . categoryPercentage ) ) / 2 ;
var fullBarHeight = categoryHeight / datasetCount ;
if ( yScale . ticks . length !== this . chart . data . labels . length ) {
var perc = yScale . ticks . length / this . chart . data . labels . length ;
fullBarHeight = fullBarHeight * perc ;
}
var barHeight = fullBarHeight * yScale . options . barPercentage ;
var barSpacing = fullBarHeight - ( fullBarHeight * yScale . options . barPercentage ) ;
return {
datasetCount : datasetCount ,
tickHeight : tickHeight ,
categoryHeight : categoryHeight ,
categorySpacing : categorySpacing ,
fullBarHeight : fullBarHeight ,
barHeight : barHeight ,
barSpacing : barSpacing ,
} ;
} ,
calculateBarHeight : function ( ) {
var yScale = this . getScaleForId ( this . getMeta ( ) . yAxisID ) ;
var ruler = this . getRuler ( ) ;
return yScale . options . stacked ? ruler . categoryHeight : ruler . barHeight ;
} ,
calculateBarX : function ( index , datasetIndex ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var value = this . getDataset ( ) . data [ index ] ;
if ( xScale . options . stacked ) {
var sumPos = 0 ,
sumNeg = 0 ;
for ( var i = 0 ; i < datasetIndex ; i ++ ) {
var ds = this . chart . data . datasets [ i ] ;
var dsMeta = this . chart . getDatasetMeta ( i ) ;
if ( dsMeta . bar && dsMeta . xAxisID === xScale . id && this . chart . isDatasetVisible ( i ) ) {
if ( ds . data [ index ] < 0 ) {
sumNeg += ds . data [ index ] || 0 ;
} else {
sumPos += ds . data [ index ] || 0 ;
}
}
}
if ( value < 0 ) {
return xScale . getPixelForValue ( sumNeg + value ) ;
} else {
return xScale . getPixelForValue ( sumPos + value ) ;
}
}
return xScale . getPixelForValue ( value ) ;
} ,
calculateBarY : function ( index , datasetIndex ) {
var meta = this . getMeta ( ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var barIndex = this . getBarIndex ( datasetIndex ) ;
var ruler = this . getRuler ( ) ;
var topTick = yScale . getPixelForValue ( null , index , datasetIndex , this . chart . isCombo ) ;
topTick -= this . chart . isCombo ? ( ruler . tickHeight / 2 ) : 0 ;
if ( yScale . options . stacked ) {
return topTick + ( ruler . categoryHeight / 2 ) + ruler . categorySpacing ;
}
return topTick +
( ruler . barHeight / 2 ) +
ruler . categorySpacing +
( ruler . barHeight * barIndex ) +
( ruler . barSpacing / 2 ) +
( ruler . barSpacing * barIndex ) ;
}
} ) ;
} ;
} , { } ] , 16 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . bubble = {
hover : {
mode : "single"
} ,
scales : {
xAxes : [ {
type : "linear" , // bubble should probably use a linear scale by default
position : "bottom" ,
id : "x-axis-0" // need an ID so datasets can reference the scale
} ] ,
yAxes : [ {
type : "linear" ,
position : "left" ,
id : "y-axis-0"
} ]
} ,
tooltips : {
callbacks : {
title : function ( tooltipItems , data ) {
// Title doesn't make sense for scatter since we format the data as a point
return '' ;
} ,
label : function ( tooltipItem , data ) {
var datasetLabel = data . datasets [ tooltipItem . datasetIndex ] . label || '' ;
var dataPoint = data . datasets [ tooltipItem . datasetIndex ] . data [ tooltipItem . index ] ;
return datasetLabel + ': (' + dataPoint . x + ', ' + dataPoint . y + ', ' + dataPoint . r + ')' ;
}
}
}
} ;
Chart . controllers . bubble = Chart . DatasetController . extend ( {
addElements : function ( ) {
var meta = this . getMeta ( ) ;
helpers . each ( this . getDataset ( ) . data , function ( value , index ) {
meta . data [ index ] = meta . data [ index ] || new Chart . elements . Point ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
} , this ) ;
} ,
addElementAndReset : function ( index ) {
var point = new Chart . elements . Point ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
// Add to the points array and reset it
this . getMeta ( ) . data . splice ( index , 0 , point ) ;
this . updateElement ( point , index , true ) ;
} ,
update : function update ( reset ) {
var meta = this . getMeta ( ) ;
var points = meta . data ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var scaleBase ;
if ( yScale . min < 0 && yScale . max < 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . max ) ;
} else if ( yScale . min > 0 && yScale . max > 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . min ) ;
} else {
scaleBase = yScale . getPixelForValue ( 0 ) ;
}
// Update Points
helpers . each ( points , function ( point , index ) {
this . updateElement ( point , index , reset ) ;
} , this ) ;
} ,
updateElement : function ( point , index , reset ) {
var meta = this . getMeta ( ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var scaleBase ;
if ( yScale . min < 0 && yScale . max < 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . max ) ;
} else if ( yScale . min > 0 && yScale . max > 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . min ) ;
} else {
scaleBase = yScale . getPixelForValue ( 0 ) ;
}
helpers . extend ( point , {
// Utility
_chart : this . chart . chart ,
_xScale : xScale ,
_yScale : yScale ,
_datasetIndex : this . index ,
_index : index ,
// Desired view properties
_model : {
x : reset ? xScale . getPixelForDecimal ( 0.5 ) : xScale . getPixelForValue ( this . getDataset ( ) . data [ index ] , index , this . index , this . chart . isCombo ) ,
y : reset ? scaleBase : yScale . getPixelForValue ( this . getDataset ( ) . data [ index ] , index , this . index ) ,
// Appearance
radius : reset ? 0 : point . custom && point . custom . radius ? point . custom . radius : this . getRadius ( this . getDataset ( ) . data [ index ] ) ,
backgroundColor : point . custom && point . custom . backgroundColor ? point . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . point . backgroundColor ) ,
borderColor : point . custom && point . custom . borderColor ? point . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . point . borderColor ) ,
borderWidth : point . custom && point . custom . borderWidth ? point . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . point . borderWidth ) ,
// Tooltip
hitRadius : point . custom && point . custom . hitRadius ? point . custom . hitRadius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . hitRadius , index , this . chart . options . elements . point . hitRadius )
}
} ) ;
point . _model . skip = point . custom && point . custom . skip ? point . custom . skip : ( isNaN ( point . _model . x ) || isNaN ( point . _model . y ) ) ;
point . pivot ( ) ;
} ,
getRadius : function ( value ) {
return value . r || this . chart . options . elements . point . radius ;
} ,
draw : function ( ease ) {
var easingDecimal = ease || 1 ;
// Transition and Draw the Points
helpers . each ( this . getMeta ( ) . data , function ( point , index ) {
point . transition ( easingDecimal ) ;
point . draw ( ) ;
} ) ;
} ,
setHoverStyle : function ( point ) {
// Point
var dataset = this . chart . data . datasets [ point . _datasetIndex ] ;
var index = point . _index ;
point . _model . radius = point . custom && point . custom . hoverRadius ? point . custom . hoverRadius : ( helpers . getValueAtIndexOrDefault ( dataset . hoverRadius , index , this . chart . options . elements . point . hoverRadius ) ) + this . getRadius ( this . getDataset ( ) . data [ point . _index ] ) ;
point . _model . backgroundColor = point . custom && point . custom . hoverBackgroundColor ? point . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBackgroundColor , index , helpers . getHoverColor ( point . _model . backgroundColor ) ) ;
point . _model . borderColor = point . custom && point . custom . hoverBorderColor ? point . custom . hoverBorderColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderColor , index , helpers . getHoverColor ( point . _model . borderColor ) ) ;
point . _model . borderWidth = point . custom && point . custom . hoverBorderWidth ? point . custom . hoverBorderWidth : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderWidth , index , point . _model . borderWidth ) ;
} ,
removeHoverStyle : function ( point ) {
var dataset = this . chart . data . datasets [ point . _datasetIndex ] ;
var index = point . _index ;
point . _model . radius = point . custom && point . custom . radius ? point . custom . radius : this . getRadius ( this . getDataset ( ) . data [ point . _index ] ) ;
point . _model . backgroundColor = point . custom && point . custom . backgroundColor ? point . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . point . backgroundColor ) ;
point . _model . borderColor = point . custom && point . custom . borderColor ? point . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . point . borderColor ) ;
point . _model . borderWidth = point . custom && point . custom . borderWidth ? point . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . point . borderWidth ) ;
}
} ) ;
} ;
} , { } ] , 17 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . doughnut = {
animation : {
//Boolean - Whether we animate the rotation of the Doughnut
animateRotate : true ,
//Boolean - Whether we animate scaling the Doughnut from the centre
animateScale : false
} ,
aspectRatio : 1 ,
hover : {
mode : 'single'
} ,
legendCallback : function ( chart ) {
var text = [ ] ;
text . push ( '<ul class="' + chart . id + '-legend">' ) ;
if ( chart . data . datasets . length ) {
for ( var i = 0 ; i < chart . data . datasets [ 0 ] . data . length ; ++ i ) {
text . push ( '<li><span style="background-color:' + chart . data . datasets [ 0 ] . backgroundColor [ i ] + '"></span>' ) ;
if ( chart . data . labels [ i ] ) {
text . push ( chart . data . labels [ i ] ) ;
}
text . push ( '</li>' ) ;
}
}
text . push ( '</ul>' ) ;
return text . join ( "" ) ;
} ,
legend : {
labels : {
generateLabels : function ( chart ) {
var data = chart . data ;
if ( data . labels . length && data . datasets . length ) {
return data . labels . map ( function ( label , i ) {
var meta = chart . getDatasetMeta ( 0 ) ;
var ds = data . datasets [ 0 ] ;
var arc = meta . data [ i ] ;
var fill = arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( ds . backgroundColor , i , this . chart . options . elements . arc . backgroundColor ) ;
var stroke = arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( ds . borderColor , i , this . chart . options . elements . arc . borderColor ) ;
var bw = arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( ds . borderWidth , i , this . chart . options . elements . arc . borderWidth ) ;
return {
text : label ,
fillStyle : fill ,
strokeStyle : stroke ,
lineWidth : bw ,
hidden : isNaN ( ds . data [ i ] ) || meta . data [ i ] . hidden ,
// Extra data used for toggling the correct item
index : i
} ;
} , this ) ;
} else {
return [ ] ;
}
}
} ,
onClick : function ( e , legendItem ) {
var index = legendItem . index ;
var chart = this . chart ;
var i , ilen , meta ;
for ( i = 0 , ilen = ( chart . data . datasets || [ ] ) . length ; i < ilen ; ++ i ) {
meta = chart . getDatasetMeta ( i ) ;
meta . data [ index ] . hidden = ! meta . data [ index ] . hidden ;
}
chart . update ( ) ;
}
} ,
//The percentage of the chart that we cut out of the middle.
cutoutPercentage : 50 ,
//The rotation of the chart, where the first data arc begins.
rotation : Math . PI * - 0.5 ,
//The total circumference of the chart.
circumference : Math . PI * 2.0 ,
// Need to override these to give a nice default
tooltips : {
callbacks : {
title : function ( ) {
return '' ;
} ,
label : function ( tooltipItem , data ) {
return data . labels [ tooltipItem . index ] + ': ' + data . datasets [ tooltipItem . datasetIndex ] . data [ tooltipItem . index ] ;
}
}
}
} ;
Chart . defaults . pie = helpers . clone ( Chart . defaults . doughnut ) ;
helpers . extend ( Chart . defaults . pie , {
cutoutPercentage : 0
} ) ;
Chart . controllers . doughnut = Chart . controllers . pie = Chart . DatasetController . extend ( {
linkScales : function ( ) {
// no scales for doughnut
} ,
addElements : function ( ) {
var meta = this . getMeta ( ) ;
helpers . each ( this . getDataset ( ) . data , function ( value , index ) {
meta . data [ index ] = meta . data [ index ] || new Chart . elements . Arc ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
} , this ) ;
} ,
addElementAndReset : function ( index , colorForNewElement ) {
var arc = new Chart . elements . Arc ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
if ( colorForNewElement && helpers . isArray ( this . getDataset ( ) . backgroundColor ) ) {
this . getDataset ( ) . backgroundColor . splice ( index , 0 , colorForNewElement ) ;
}
// Add to the points array and reset it
this . getMeta ( ) . data . splice ( index , 0 , arc ) ;
this . updateElement ( arc , index , true ) ;
} ,
// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
getRingIndex : function getRingIndex ( datasetIndex ) {
var ringIndex = 0 ;
for ( var j = 0 ; j < datasetIndex ; ++ j ) {
if ( this . chart . isDatasetVisible ( j ) ) {
++ ringIndex ;
}
}
return ringIndex ;
} ,
update : function update ( reset ) {
var availableWidth = this . chart . chartArea . right - this . chart . chartArea . left - this . chart . options . elements . arc . borderWidth ;
var availableHeight = this . chart . chartArea . bottom - this . chart . chartArea . top - this . chart . options . elements . arc . borderWidth ;
var minSize = Math . min ( availableWidth , availableHeight ) ;
var offset = { x : 0 , y : 0 } ;
// If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
if ( this . chart . options . circumference < Math . PI * 2.0 ) {
var startAngle = this . chart . options . rotation % ( Math . PI * 2.0 ) ;
startAngle += Math . PI * 2.0 * ( startAngle >= Math . PI ? - 1 : startAngle < - Math . PI ? 1 : 0 ) ;
var endAngle = startAngle + this . chart . options . circumference ;
var start = { x : Math . cos ( startAngle ) , y : Math . sin ( startAngle ) } ;
var end = { x : Math . cos ( endAngle ) , y : Math . sin ( endAngle ) } ;
var contains0 = ( startAngle <= 0 && 0 <= endAngle ) || ( startAngle <= Math . PI * 2.0 && Math . PI * 2.0 <= endAngle ) ;
var contains90 = ( startAngle <= Math . PI * 0.5 && Math . PI * 0.5 <= endAngle ) || ( startAngle <= Math . PI * 2.5 && Math . PI * 2.5 <= endAngle ) ;
var contains180 = ( startAngle <= - Math . PI && - Math . PI <= endAngle ) || ( startAngle <= Math . PI && Math . PI <= endAngle ) ;
var contains270 = ( startAngle <= - Math . PI * 0.5 && - Math . PI * 0.5 <= endAngle ) || ( startAngle <= Math . PI * 1.5 && Math . PI * 1.5 <= endAngle ) ;
var cutout = this . chart . options . cutoutPercentage / 100.0 ;
var min = { x : contains180 ? - 1 : Math . min ( start . x * ( start . x < 0 ? 1 : cutout ) , end . x * ( end . x < 0 ? 1 : cutout ) ) , y : contains270 ? - 1 : Math . min ( start . y * ( start . y < 0 ? 1 : cutout ) , end . y * ( end . y < 0 ? 1 : cutout ) ) } ;
var max = { x : contains0 ? 1 : Math . max ( start . x * ( start . x > 0 ? 1 : cutout ) , end . x * ( end . x > 0 ? 1 : cutout ) ) , y : contains90 ? 1 : Math . max ( start . y * ( start . y > 0 ? 1 : cutout ) , end . y * ( end . y > 0 ? 1 : cutout ) ) } ;
var size = { width : ( max . x - min . x ) * 0.5 , height : ( max . y - min . y ) * 0.5 } ;
minSize = Math . min ( availableWidth / size . width , availableHeight / size . height ) ;
offset = { x : ( max . x + min . x ) * - 0.5 , y : ( max . y + min . y ) * - 0.5 } ;
}
this . chart . outerRadius = Math . max ( minSize / 2 , 0 ) ;
this . chart . innerRadius = Math . max ( this . chart . options . cutoutPercentage ? ( this . chart . outerRadius / 100 ) * ( this . chart . options . cutoutPercentage ) : 1 , 0 ) ;
this . chart . radiusLength = ( this . chart . outerRadius - this . chart . innerRadius ) / this . chart . getVisibleDatasetCount ( ) ;
this . chart . offsetX = offset . x * this . chart . outerRadius ;
this . chart . offsetY = offset . y * this . chart . outerRadius ;
this . getMeta ( ) . total = this . calculateTotal ( ) ;
this . outerRadius = this . chart . outerRadius - ( this . chart . radiusLength * this . getRingIndex ( this . index ) ) ;
this . innerRadius = this . outerRadius - this . chart . radiusLength ;
helpers . each ( this . getMeta ( ) . data , function ( arc , index ) {
this . updateElement ( arc , index , reset ) ;
} , this ) ;
} ,
updateElement : function ( arc , index , reset ) {
var centerX = ( this . chart . chartArea . left + this . chart . chartArea . right ) / 2 ;
var centerY = ( this . chart . chartArea . top + this . chart . chartArea . bottom ) / 2 ;
var startAngle = this . chart . options . rotation ; // non reset case handled later
var endAngle = this . chart . options . rotation ; // non reset case handled later
var circumference = reset && this . chart . options . animation . animateRotate ? 0 : arc . hidden ? 0 : this . calculateCircumference ( this . getDataset ( ) . data [ index ] ) * ( this . chart . options . circumference / ( 2.0 * Math . PI ) ) ;
var innerRadius = reset && this . chart . options . animation . animateScale ? 0 : this . innerRadius ;
var outerRadius = reset && this . chart . options . animation . animateScale ? 0 : this . outerRadius ;
helpers . extend ( arc , {
// Utility
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index ,
// Desired view properties
_model : {
x : centerX + this . chart . offsetX ,
y : centerY + this . chart . offsetY ,
startAngle : startAngle ,
endAngle : endAngle ,
circumference : circumference ,
outerRadius : outerRadius ,
innerRadius : innerRadius ,
backgroundColor : arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . arc . backgroundColor ) ,
hoverBackgroundColor : arc . custom && arc . custom . hoverBackgroundColor ? arc . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . hoverBackgroundColor , index , this . chart . options . elements . arc . hoverBackgroundColor ) ,
borderWidth : arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . arc . borderWidth ) ,
borderColor : arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . arc . borderColor ) ,
label : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . label , index , this . chart . data . labels [ index ] )
}
} ) ;
// Set correct angles if not resetting
if ( ! reset || ! this . chart . options . animation . animateRotate ) {
if ( index === 0 ) {
arc . _model . startAngle = this . chart . options . rotation ;
} else {
arc . _model . startAngle = this . getMeta ( ) . data [ index - 1 ] . _model . endAngle ;
}
arc . _model . endAngle = arc . _model . startAngle + arc . _model . circumference ;
}
arc . pivot ( ) ;
} ,
draw : function ( ease ) {
var easingDecimal = ease || 1 ;
helpers . each ( this . getMeta ( ) . data , function ( arc , index ) {
arc . transition ( easingDecimal ) . draw ( ) ;
} ) ;
} ,
setHoverStyle : function ( arc ) {
var dataset = this . chart . data . datasets [ arc . _datasetIndex ] ;
var index = arc . _index ;
arc . _model . backgroundColor = arc . custom && arc . custom . hoverBackgroundColor ? arc . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBackgroundColor , index , helpers . getHoverColor ( arc . _model . backgroundColor ) ) ;
arc . _model . borderColor = arc . custom && arc . custom . hoverBorderColor ? arc . custom . hoverBorderColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderColor , index , helpers . getHoverColor ( arc . _model . borderColor ) ) ;
arc . _model . borderWidth = arc . custom && arc . custom . hoverBorderWidth ? arc . custom . hoverBorderWidth : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderWidth , index , arc . _model . borderWidth ) ;
} ,
removeHoverStyle : function ( arc ) {
var dataset = this . chart . data . datasets [ arc . _datasetIndex ] ;
var index = arc . _index ;
arc . _model . backgroundColor = arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . arc . backgroundColor ) ;
arc . _model . borderColor = arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . arc . borderColor ) ;
arc . _model . borderWidth = arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . arc . borderWidth ) ;
} ,
calculateTotal : function ( ) {
var dataset = this . getDataset ( ) ;
var meta = this . getMeta ( ) ;
var total = 0 ;
var value ;
helpers . each ( meta . data , function ( element , index ) {
value = dataset . data [ index ] ;
if ( ! isNaN ( value ) && ! element . hidden ) {
total += Math . abs ( value ) ;
}
} ) ;
return total ;
} ,
calculateCircumference : function ( value ) {
var total = this . getMeta ( ) . total ;
if ( total > 0 && ! isNaN ( value ) ) {
return ( Math . PI * 2.0 ) * ( value / total ) ;
} else {
return 0 ;
}
}
} ) ;
} ;
} , { } ] , 18 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . line = {
showLines : true ,
hover : {
mode : "label"
} ,
scales : {
xAxes : [ {
type : "category" ,
id : 'x-axis-0'
} ] ,
yAxes : [ {
type : "linear" ,
id : 'y-axis-0'
} ]
}
} ;
Chart . controllers . line = Chart . DatasetController . extend ( {
addElements : function ( ) {
var meta = this . getMeta ( ) ;
meta . dataset = meta . dataset || new Chart . elements . Line ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_points : meta . data
} ) ;
helpers . each ( this . getDataset ( ) . data , function ( value , index ) {
meta . data [ index ] = meta . data [ index ] || new Chart . elements . Point ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
} , this ) ;
} ,
addElementAndReset : function ( index ) {
var point = new Chart . elements . Point ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
// Add to the points array and reset it
this . getMeta ( ) . data . splice ( index , 0 , point ) ;
this . updateElement ( point , index , true ) ;
// Make sure bezier control points are updated
if ( this . chart . options . showLines && this . chart . options . elements . line . tension !== 0 )
this . updateBezierControlPoints ( ) ;
} ,
update : function update ( reset ) {
var meta = this . getMeta ( ) ;
var line = meta . dataset ;
var points = meta . data ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var scaleBase ;
if ( yScale . min < 0 && yScale . max < 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . max ) ;
} else if ( yScale . min > 0 && yScale . max > 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . min ) ;
} else {
scaleBase = yScale . getPixelForValue ( 0 ) ;
}
// Update Line
if ( this . chart . options . showLines ) {
// Utility
line . _scale = yScale ;
line . _datasetIndex = this . index ;
// Data
line . _children = points ;
// Model
// Compatibility: If the properties are defined with only the old name, use those values
if ( ( this . getDataset ( ) . tension !== undefined ) && ( this . getDataset ( ) . lineTension === undefined ) )
{
this . getDataset ( ) . lineTension = this . getDataset ( ) . tension ;
}
line . _model = {
// Appearance
tension : line . custom && line . custom . tension ? line . custom . tension : helpers . getValueOrDefault ( this . getDataset ( ) . lineTension , this . chart . options . elements . line . tension ) ,
backgroundColor : line . custom && line . custom . backgroundColor ? line . custom . backgroundColor : ( this . getDataset ( ) . backgroundColor || this . chart . options . elements . line . backgroundColor ) ,
borderWidth : line . custom && line . custom . borderWidth ? line . custom . borderWidth : ( this . getDataset ( ) . borderWidth || this . chart . options . elements . line . borderWidth ) ,
borderColor : line . custom && line . custom . borderColor ? line . custom . borderColor : ( this . getDataset ( ) . borderColor || this . chart . options . elements . line . borderColor ) ,
borderCapStyle : line . custom && line . custom . borderCapStyle ? line . custom . borderCapStyle : ( this . getDataset ( ) . borderCapStyle || this . chart . options . elements . line . borderCapStyle ) ,
borderDash : line . custom && line . custom . borderDash ? line . custom . borderDash : ( this . getDataset ( ) . borderDash || this . chart . options . elements . line . borderDash ) ,
borderDashOffset : line . custom && line . custom . borderDashOffset ? line . custom . borderDashOffset : ( this . getDataset ( ) . borderDashOffset || this . chart . options . elements . line . borderDashOffset ) ,
borderJoinStyle : line . custom && line . custom . borderJoinStyle ? line . custom . borderJoinStyle : ( this . getDataset ( ) . borderJoinStyle || this . chart . options . elements . line . borderJoinStyle ) ,
fill : line . custom && line . custom . fill ? line . custom . fill : ( this . getDataset ( ) . fill !== undefined ? this . getDataset ( ) . fill : this . chart . options . elements . line . fill ) ,
// Scale
scaleTop : yScale . top ,
scaleBottom : yScale . bottom ,
scaleZero : scaleBase
} ;
line . pivot ( ) ;
}
// Update Points
helpers . each ( points , function ( point , index ) {
this . updateElement ( point , index , reset ) ;
} , this ) ;
if ( this . chart . options . showLines && this . chart . options . elements . line . tension !== 0 )
this . updateBezierControlPoints ( ) ;
} ,
getPointBackgroundColor : function ( point , index ) {
var backgroundColor = this . chart . options . elements . point . backgroundColor ;
var dataset = this . getDataset ( ) ;
if ( point . custom && point . custom . backgroundColor ) {
backgroundColor = point . custom . backgroundColor ;
} else if ( dataset . pointBackgroundColor ) {
backgroundColor = helpers . getValueAtIndexOrDefault ( dataset . pointBackgroundColor , index , backgroundColor ) ;
} else if ( dataset . backgroundColor ) {
backgroundColor = dataset . backgroundColor ;
}
return backgroundColor ;
} ,
getPointBorderColor : function ( point , index ) {
var borderColor = this . chart . options . elements . point . borderColor ;
var dataset = this . getDataset ( ) ;
if ( point . custom && point . custom . borderColor ) {
borderColor = point . custom . borderColor ;
} else if ( dataset . pointBorderColor ) {
borderColor = helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBorderColor , index , borderColor ) ;
} else if ( dataset . borderColor ) {
borderColor = dataset . borderColor ;
}
return borderColor ;
} ,
getPointBorderWidth : function ( point , index ) {
var borderWidth = this . chart . options . elements . point . borderWidth ;
var dataset = this . getDataset ( ) ;
if ( point . custom && point . custom . borderWidth !== undefined ) {
borderWidth = point . custom . borderWidth ;
} else if ( dataset . pointBorderWidth !== undefined ) {
borderWidth = helpers . getValueAtIndexOrDefault ( dataset . pointBorderWidth , index , borderWidth ) ;
} else if ( dataset . borderWidth !== undefined ) {
borderWidth = dataset . borderWidth ;
}
return borderWidth ;
} ,
updateElement : function ( point , index , reset ) {
var meta = this . getMeta ( ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var scaleBase ;
if ( yScale . min < 0 && yScale . max < 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . max ) ;
} else if ( yScale . min > 0 && yScale . max > 0 ) {
scaleBase = yScale . getPixelForValue ( yScale . min ) ;
} else {
scaleBase = yScale . getPixelForValue ( 0 ) ;
}
// Utility
point . _chart = this . chart . chart ;
point . _xScale = xScale ;
point . _yScale = yScale ;
point . _datasetIndex = this . index ;
point . _index = index ;
// Desired view properties
// Compatibility: If the properties are defined with only the old name, use those values
if ( ( this . getDataset ( ) . radius !== undefined ) && ( this . getDataset ( ) . pointRadius === undefined ) )
{
this . getDataset ( ) . pointRadius = this . getDataset ( ) . radius ;
}
if ( ( this . getDataset ( ) . hitRadius !== undefined ) && ( this . getDataset ( ) . pointHitRadius === undefined ) )
{
this . getDataset ( ) . pointHitRadius = this . getDataset ( ) . hitRadius ;
}
point . _model = {
x : xScale . getPixelForValue ( this . getDataset ( ) . data [ index ] , index , this . index , this . chart . isCombo ) ,
y : reset ? scaleBase : this . calculatePointY ( this . getDataset ( ) . data [ index ] , index , this . index , this . chart . isCombo ) ,
// Appearance
radius : point . custom && point . custom . radius ? point . custom . radius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointRadius , index , this . chart . options . elements . point . radius ) ,
pointStyle : point . custom && point . custom . pointStyle ? point . custom . pointStyle : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointStyle , index , this . chart . options . elements . point . pointStyle ) ,
backgroundColor : this . getPointBackgroundColor ( point , index ) ,
borderColor : this . getPointBorderColor ( point , index ) ,
borderWidth : this . getPointBorderWidth ( point , index ) ,
tension : meta . dataset . _model ? meta . dataset . _model . tension : 0 ,
// Tooltip
hitRadius : point . custom && point . custom . hitRadius ? point . custom . hitRadius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointHitRadius , index , this . chart . options . elements . point . hitRadius )
} ;
point . _model . skip = point . custom && point . custom . skip ? point . custom . skip : ( isNaN ( point . _model . x ) || isNaN ( point . _model . y ) ) ;
} ,
calculatePointY : function ( value , index , datasetIndex , isCombo ) {
var meta = this . getMeta ( ) ;
var xScale = this . getScaleForId ( meta . xAxisID ) ;
var yScale = this . getScaleForId ( meta . yAxisID ) ;
if ( yScale . options . stacked ) {
var sumPos = 0 ,
sumNeg = 0 ;
for ( var i = 0 ; i < datasetIndex ; i ++ ) {
var ds = this . chart . data . datasets [ i ] ;
var dsMeta = this . chart . getDatasetMeta ( i ) ;
if ( dsMeta . type === 'line' && this . chart . isDatasetVisible ( i ) ) {
if ( ds . data [ index ] < 0 ) {
sumNeg += ds . data [ index ] || 0 ;
} else {
sumPos += ds . data [ index ] || 0 ;
}
}
}
if ( value < 0 ) {
return yScale . getPixelForValue ( sumNeg + value ) ;
} else {
return yScale . getPixelForValue ( sumPos + value ) ;
}
}
return yScale . getPixelForValue ( value ) ;
} ,
updateBezierControlPoints : function ( ) {
// Update bezier control points
var meta = this . getMeta ( ) ;
helpers . each ( meta . data , function ( point , index ) {
var controlPoints = helpers . splineCurve (
helpers . previousItem ( meta . data , index ) . _model ,
point . _model ,
helpers . nextItem ( meta . data , index ) . _model ,
meta . dataset . _model . tension
) ;
// Prevent the bezier going outside of the bounds of the graph
point . _model . controlPointPreviousX = Math . max ( Math . min ( controlPoints . previous . x , this . chart . chartArea . right ) , this . chart . chartArea . left ) ;
point . _model . controlPointPreviousY = Math . max ( Math . min ( controlPoints . previous . y , this . chart . chartArea . bottom ) , this . chart . chartArea . top ) ;
point . _model . controlPointNextX = Math . max ( Math . min ( controlPoints . next . x , this . chart . chartArea . right ) , this . chart . chartArea . left ) ;
point . _model . controlPointNextY = Math . max ( Math . min ( controlPoints . next . y , this . chart . chartArea . bottom ) , this . chart . chartArea . top ) ;
// Now pivot the point for animation
point . pivot ( ) ;
} , this ) ;
} ,
draw : function ( ease ) {
var meta = this . getMeta ( ) ;
var easingDecimal = ease || 1 ;
// Transition Point Locations
helpers . each ( meta . data , function ( point ) {
point . transition ( easingDecimal ) ;
} ) ;
// Transition and Draw the line
if ( this . chart . options . showLines )
meta . dataset . transition ( easingDecimal ) . draw ( ) ;
// Draw the points
helpers . each ( meta . data , function ( point ) {
point . draw ( ) ;
} ) ;
} ,
setHoverStyle : function ( point ) {
// Point
var dataset = this . chart . data . datasets [ point . _datasetIndex ] ;
var index = point . _index ;
point . _model . radius = point . custom && point . custom . hoverRadius ? point . custom . hoverRadius : helpers . getValueAtIndexOrDefault ( dataset . pointHoverRadius , index , this . chart . options . elements . point . hoverRadius ) ;
point . _model . backgroundColor = point . custom && point . custom . hoverBackgroundColor ? point . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( dataset . pointHoverBackgroundColor , index , helpers . getHoverColor ( point . _model . backgroundColor ) ) ;
point . _model . borderColor = point . custom && point . custom . hoverBorderColor ? point . custom . hoverBorderColor : helpers . getValueAtIndexOrDefault ( dataset . pointHoverBorderColor , index , helpers . getHoverColor ( point . _model . borderColor ) ) ;
point . _model . borderWidth = point . custom && point . custom . hoverBorderWidth ? point . custom . hoverBorderWidth : helpers . getValueAtIndexOrDefault ( dataset . pointHoverBorderWidth , index , point . _model . borderWidth ) ;
} ,
removeHoverStyle : function ( point ) {
var dataset = this . chart . data . datasets [ point . _datasetIndex ] ;
var index = point . _index ;
// Compatibility: If the properties are defined with only the old name, use those values
if ( ( this . getDataset ( ) . radius !== undefined ) && ( this . getDataset ( ) . pointRadius === undefined ) )
{
this . getDataset ( ) . pointRadius = this . getDataset ( ) . radius ;
}
point . _model . radius = point . custom && point . custom . radius ? point . custom . radius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointRadius , index , this . chart . options . elements . point . radius ) ;
point . _model . backgroundColor = this . getPointBackgroundColor ( point , index ) ;
point . _model . borderColor = this . getPointBorderColor ( point , index ) ;
point . _model . borderWidth = this . getPointBorderWidth ( point , index ) ;
}
} ) ;
} ;
} , { } ] , 19 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . polarArea = {
scale : {
type : "radialLinear" ,
lineArc : true // so that lines are circular
} ,
//Boolean - Whether to animate the rotation of the chart
animation : {
animateRotate : true ,
animateScale : true
} ,
aspectRatio : 1 ,
legendCallback : function ( chart ) {
var text = [ ] ;
text . push ( '<ul class="' + chart . id + '-legend">' ) ;
if ( chart . data . datasets . length ) {
for ( var i = 0 ; i < chart . data . datasets [ 0 ] . data . length ; ++ i ) {
text . push ( '<li><span style="background-color:' + chart . data . datasets [ 0 ] . backgroundColor [ i ] + '">' ) ;
if ( chart . data . labels [ i ] ) {
text . push ( chart . data . labels [ i ] ) ;
}
text . push ( '</span></li>' ) ;
}
}
text . push ( '</ul>' ) ;
return text . join ( "" ) ;
} ,
legend : {
labels : {
generateLabels : function ( chart ) {
var data = chart . data ;
if ( data . labels . length && data . datasets . length ) {
return data . labels . map ( function ( label , i ) {
var meta = chart . getDatasetMeta ( 0 ) ;
var ds = data . datasets [ 0 ] ;
var arc = meta . data [ i ] ;
var fill = arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( ds . backgroundColor , i , this . chart . options . elements . arc . backgroundColor ) ;
var stroke = arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( ds . borderColor , i , this . chart . options . elements . arc . borderColor ) ;
var bw = arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( ds . borderWidth , i , this . chart . options . elements . arc . borderWidth ) ;
return {
text : label ,
fillStyle : fill ,
strokeStyle : stroke ,
lineWidth : bw ,
hidden : isNaN ( ds . data [ i ] ) || meta . data [ i ] . hidden ,
// Extra data used for toggling the correct item
index : i
} ;
} , this ) ;
} else {
return [ ] ;
}
}
} ,
onClick : function ( e , legendItem ) {
var index = legendItem . index ;
var chart = this . chart ;
var i , ilen , meta ;
for ( i = 0 , ilen = ( chart . data . datasets || [ ] ) . length ; i < ilen ; ++ i ) {
meta = chart . getDatasetMeta ( i ) ;
meta . data [ index ] . hidden = ! meta . data [ index ] . hidden ;
}
chart . update ( ) ;
}
} ,
// Need to override these to give a nice default
tooltips : {
callbacks : {
title : function ( ) {
return '' ;
} ,
label : function ( tooltipItem , data ) {
return data . labels [ tooltipItem . index ] + ': ' + tooltipItem . yLabel ;
}
}
}
} ;
Chart . controllers . polarArea = Chart . DatasetController . extend ( {
linkScales : function ( ) {
// no scales for doughnut
} ,
addElements : function ( ) {
var meta = this . getMeta ( ) ;
helpers . each ( this . getDataset ( ) . data , function ( value , index ) {
meta . data [ index ] = meta . data [ index ] || new Chart . elements . Arc ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
} , this ) ;
} ,
addElementAndReset : function ( index ) {
var arc = new Chart . elements . Arc ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
// Add to the points array and reset it
this . getMeta ( ) . data . splice ( index , 0 , arc ) ;
this . updateElement ( arc , index , true ) ;
} ,
update : function update ( reset ) {
var meta = this . getMeta ( ) ;
var minSize = Math . min ( this . chart . chartArea . right - this . chart . chartArea . left , this . chart . chartArea . bottom - this . chart . chartArea . top ) ;
this . chart . outerRadius = Math . max ( ( minSize - this . chart . options . elements . arc . borderWidth / 2 ) / 2 , 0 ) ;
this . chart . innerRadius = Math . max ( this . chart . options . cutoutPercentage ? ( this . chart . outerRadius / 100 ) * ( this . chart . options . cutoutPercentage ) : 1 , 0 ) ;
this . chart . radiusLength = ( this . chart . outerRadius - this . chart . innerRadius ) / this . chart . getVisibleDatasetCount ( ) ;
this . outerRadius = this . chart . outerRadius - ( this . chart . radiusLength * this . index ) ;
this . innerRadius = this . outerRadius - this . chart . radiusLength ;
meta . count = this . countVisibleElements ( ) ;
helpers . each ( meta . data , function ( arc , index ) {
this . updateElement ( arc , index , reset ) ;
} , this ) ;
} ,
updateElement : function ( arc , index , reset ) {
var circumference = this . calculateCircumference ( this . getDataset ( ) . data [ index ] ) ;
var centerX = ( this . chart . chartArea . left + this . chart . chartArea . right ) / 2 ;
var centerY = ( this . chart . chartArea . top + this . chart . chartArea . bottom ) / 2 ;
// If there is NaN data before us, we need to calculate the starting angle correctly.
// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
var visibleCount = 0 ;
var meta = this . getMeta ( ) ;
for ( var i = 0 ; i < index ; ++ i ) {
if ( ! isNaN ( this . getDataset ( ) . data [ i ] ) && ! meta . data [ i ] . hidden ) {
++ visibleCount ;
}
}
var distance = arc . hidden ? 0 : this . chart . scale . getDistanceFromCenterForValue ( this . getDataset ( ) . data [ index ] ) ;
var startAngle = ( - 0.5 * Math . PI ) + ( circumference * visibleCount ) ;
var endAngle = startAngle + ( arc . hidden ? 0 : circumference ) ;
var resetModel = {
x : centerX ,
y : centerY ,
innerRadius : 0 ,
outerRadius : this . chart . options . animation . animateScale ? 0 : this . chart . scale . getDistanceFromCenterForValue ( this . getDataset ( ) . data [ index ] ) ,
startAngle : this . chart . options . animation . animateRotate ? Math . PI * - 0.5 : startAngle ,
endAngle : this . chart . options . animation . animateRotate ? Math . PI * - 0.5 : endAngle ,
backgroundColor : arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . arc . backgroundColor ) ,
borderWidth : arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . arc . borderWidth ) ,
borderColor : arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . arc . borderColor ) ,
label : helpers . getValueAtIndexOrDefault ( this . chart . data . labels , index , this . chart . data . labels [ index ] )
} ;
helpers . extend ( arc , {
// Utility
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index ,
_scale : this . chart . scale ,
// Desired view properties
_model : reset ? resetModel : {
x : centerX ,
y : centerY ,
innerRadius : 0 ,
outerRadius : distance ,
startAngle : startAngle ,
endAngle : endAngle ,
backgroundColor : arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . arc . backgroundColor ) ,
borderWidth : arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . arc . borderWidth ) ,
borderColor : arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . arc . borderColor ) ,
label : helpers . getValueAtIndexOrDefault ( this . chart . data . labels , index , this . chart . data . labels [ index ] )
}
} ) ;
arc . pivot ( ) ;
} ,
draw : function ( ease ) {
var easingDecimal = ease || 1 ;
helpers . each ( this . getMeta ( ) . data , function ( arc , index ) {
arc . transition ( easingDecimal ) . draw ( ) ;
} ) ;
} ,
setHoverStyle : function ( arc ) {
var dataset = this . chart . data . datasets [ arc . _datasetIndex ] ;
var index = arc . _index ;
arc . _model . backgroundColor = arc . custom && arc . custom . hoverBackgroundColor ? arc . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBackgroundColor , index , helpers . getHoverColor ( arc . _model . backgroundColor ) ) ;
arc . _model . borderColor = arc . custom && arc . custom . hoverBorderColor ? arc . custom . hoverBorderColor : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderColor , index , helpers . getHoverColor ( arc . _model . borderColor ) ) ;
arc . _model . borderWidth = arc . custom && arc . custom . hoverBorderWidth ? arc . custom . hoverBorderWidth : helpers . getValueAtIndexOrDefault ( dataset . hoverBorderWidth , index , arc . _model . borderWidth ) ;
} ,
removeHoverStyle : function ( arc ) {
var dataset = this . chart . data . datasets [ arc . _datasetIndex ] ;
var index = arc . _index ;
arc . _model . backgroundColor = arc . custom && arc . custom . backgroundColor ? arc . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . backgroundColor , index , this . chart . options . elements . arc . backgroundColor ) ;
arc . _model . borderColor = arc . custom && arc . custom . borderColor ? arc . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderColor , index , this . chart . options . elements . arc . borderColor ) ;
arc . _model . borderWidth = arc . custom && arc . custom . borderWidth ? arc . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . borderWidth , index , this . chart . options . elements . arc . borderWidth ) ;
} ,
countVisibleElements : function ( ) {
var dataset = this . getDataset ( ) ;
var meta = this . getMeta ( ) ;
var count = 0 ;
helpers . each ( meta . data , function ( element , index ) {
if ( ! isNaN ( dataset . data [ index ] ) && ! element . hidden ) {
count ++ ;
}
} ) ;
return count ;
} ,
calculateCircumference : function ( value ) {
var count = this . getMeta ( ) . count ;
if ( count > 0 && ! isNaN ( value ) ) {
return ( 2 * Math . PI ) / count ;
} else {
return 0 ;
}
}
} ) ;
} ;
} , { } ] , 20 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . radar = {
scale : {
type : "radialLinear"
} ,
elements : {
line : {
tension : 0 // no bezier in radar
}
}
} ;
Chart . controllers . radar = Chart . DatasetController . extend ( {
linkScales : function ( ) {
// No need. Single scale only
} ,
addElements : function ( ) {
var meta = this . getMeta ( ) ;
meta . dataset = meta . dataset || new Chart . elements . Line ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_points : meta . data ,
_loop : true
} ) ;
helpers . each ( this . getDataset ( ) . data , function ( value , index ) {
meta . data [ index ] = meta . data [ index ] || new Chart . elements . Point ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index ,
_model : {
x : 0 , //xScale.getPixelForValue(null, index, true),
y : 0 //this.chartArea.bottom,
}
} ) ;
} , this ) ;
} ,
addElementAndReset : function ( index ) {
var point = new Chart . elements . Point ( {
_chart : this . chart . chart ,
_datasetIndex : this . index ,
_index : index
} ) ;
// Add to the points array and reset it
this . getMeta ( ) . data . splice ( index , 0 , point ) ;
this . updateElement ( point , index , true ) ;
// Make sure bezier control points are updated
this . updateBezierControlPoints ( ) ;
} ,
update : function update ( reset ) {
var meta = this . getMeta ( ) ;
var line = meta . dataset ;
var points = meta . data ;
var scale = this . chart . scale ;
var scaleBase ;
if ( scale . min < 0 && scale . max < 0 ) {
scaleBase = scale . getPointPositionForValue ( 0 , scale . max ) ;
} else if ( scale . min > 0 && scale . max > 0 ) {
scaleBase = scale . getPointPositionForValue ( 0 , scale . min ) ;
} else {
scaleBase = scale . getPointPositionForValue ( 0 , 0 ) ;
}
// Compatibility: If the properties are defined with only the old name, use those values
if ( ( this . getDataset ( ) . tension !== undefined ) && ( this . getDataset ( ) . lineTension === undefined ) )
{
this . getDataset ( ) . lineTension = this . getDataset ( ) . tension ;
}
helpers . extend ( meta . dataset , {
// Utility
_datasetIndex : this . index ,
// Data
_children : points ,
// Model
_model : {
// Appearance
tension : line . custom && line . custom . tension ? line . custom . tension : helpers . getValueOrDefault ( this . getDataset ( ) . lineTension , this . chart . options . elements . line . tension ) ,
backgroundColor : line . custom && line . custom . backgroundColor ? line . custom . backgroundColor : ( this . getDataset ( ) . backgroundColor || this . chart . options . elements . line . backgroundColor ) ,
borderWidth : line . custom && line . custom . borderWidth ? line . custom . borderWidth : ( this . getDataset ( ) . borderWidth || this . chart . options . elements . line . borderWidth ) ,
borderColor : line . custom && line . custom . borderColor ? line . custom . borderColor : ( this . getDataset ( ) . borderColor || this . chart . options . elements . line . borderColor ) ,
fill : line . custom && line . custom . fill ? line . custom . fill : ( this . getDataset ( ) . fill !== undefined ? this . getDataset ( ) . fill : this . chart . options . elements . line . fill ) ,
borderCapStyle : line . custom && line . custom . borderCapStyle ? line . custom . borderCapStyle : ( this . getDataset ( ) . borderCapStyle || this . chart . options . elements . line . borderCapStyle ) ,
borderDash : line . custom && line . custom . borderDash ? line . custom . borderDash : ( this . getDataset ( ) . borderDash || this . chart . options . elements . line . borderDash ) ,
borderDashOffset : line . custom && line . custom . borderDashOffset ? line . custom . borderDashOffset : ( this . getDataset ( ) . borderDashOffset || this . chart . options . elements . line . borderDashOffset ) ,
borderJoinStyle : line . custom && line . custom . borderJoinStyle ? line . custom . borderJoinStyle : ( this . getDataset ( ) . borderJoinStyle || this . chart . options . elements . line . borderJoinStyle ) ,
// Scale
scaleTop : scale . top ,
scaleBottom : scale . bottom ,
scaleZero : scaleBase
}
} ) ;
meta . dataset . pivot ( ) ;
// Update Points
helpers . each ( points , function ( point , index ) {
this . updateElement ( point , index , reset ) ;
} , this ) ;
// Update bezier control points
this . updateBezierControlPoints ( ) ;
} ,
updateElement : function ( point , index , reset ) {
var pointPosition = this . chart . scale . getPointPositionForValue ( index , this . getDataset ( ) . data [ index ] ) ;
helpers . extend ( point , {
// Utility
_datasetIndex : this . index ,
_index : index ,
_scale : this . chart . scale ,
// Desired view properties
_model : {
x : reset ? this . chart . scale . xCenter : pointPosition . x , // value not used in dataset scale, but we want a consistent API between scales
y : reset ? this . chart . scale . yCenter : pointPosition . y ,
// Appearance
tension : point . custom && point . custom . tension ? point . custom . tension : helpers . getValueOrDefault ( this . getDataset ( ) . tension , this . chart . options . elements . line . tension ) ,
radius : point . custom && point . custom . radius ? point . custom . radius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointRadius , index , this . chart . options . elements . point . radius ) ,
backgroundColor : point . custom && point . custom . backgroundColor ? point . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBackgroundColor , index , this . chart . options . elements . point . backgroundColor ) ,
borderColor : point . custom && point . custom . borderColor ? point . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBorderColor , index , this . chart . options . elements . point . borderColor ) ,
borderWidth : point . custom && point . custom . borderWidth ? point . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBorderWidth , index , this . chart . options . elements . point . borderWidth ) ,
pointStyle : point . custom && point . custom . pointStyle ? point . custom . pointStyle : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointStyle , index , this . chart . options . elements . point . pointStyle ) ,
// Tooltip
hitRadius : point . custom && point . custom . hitRadius ? point . custom . hitRadius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . hitRadius , index , this . chart . options . elements . point . hitRadius )
}
} ) ;
point . _model . skip = point . custom && point . custom . skip ? point . custom . skip : ( isNaN ( point . _model . x ) || isNaN ( point . _model . y ) ) ;
} ,
updateBezierControlPoints : function ( ) {
var meta = this . getMeta ( ) ;
helpers . each ( meta . data , function ( point , index ) {
var controlPoints = helpers . splineCurve (
helpers . previousItem ( meta . data , index , true ) . _model ,
point . _model ,
helpers . nextItem ( meta . data , index , true ) . _model ,
point . _model . tension
) ;
// Prevent the bezier going outside of the bounds of the graph
point . _model . controlPointPreviousX = Math . max ( Math . min ( controlPoints . previous . x , this . chart . chartArea . right ) , this . chart . chartArea . left ) ;
point . _model . controlPointPreviousY = Math . max ( Math . min ( controlPoints . previous . y , this . chart . chartArea . bottom ) , this . chart . chartArea . top ) ;
point . _model . controlPointNextX = Math . max ( Math . min ( controlPoints . next . x , this . chart . chartArea . right ) , this . chart . chartArea . left ) ;
point . _model . controlPointNextY = Math . max ( Math . min ( controlPoints . next . y , this . chart . chartArea . bottom ) , this . chart . chartArea . top ) ;
// Now pivot the point for animation
point . pivot ( ) ;
} , this ) ;
} ,
draw : function ( ease ) {
var meta = this . getMeta ( ) ;
var easingDecimal = ease || 1 ;
// Transition Point Locations
helpers . each ( meta . data , function ( point , index ) {
point . transition ( easingDecimal ) ;
} ) ;
// Transition and Draw the line
meta . dataset . transition ( easingDecimal ) . draw ( ) ;
// Draw the points
helpers . each ( meta . data , function ( point ) {
point . draw ( ) ;
} ) ;
} ,
setHoverStyle : function ( point ) {
// Point
var dataset = this . chart . data . datasets [ point . _datasetIndex ] ;
var index = point . _index ;
point . _model . radius = point . custom && point . custom . hoverRadius ? point . custom . hoverRadius : helpers . getValueAtIndexOrDefault ( dataset . pointHoverRadius , index , this . chart . options . elements . point . hoverRadius ) ;
point . _model . backgroundColor = point . custom && point . custom . hoverBackgroundColor ? point . custom . hoverBackgroundColor : helpers . getValueAtIndexOrDefault ( dataset . pointHoverBackgroundColor , index , helpers . getHoverColor ( point . _model . backgroundColor ) ) ;
point . _model . borderColor = point . custom && point . custom . hoverBorderColor ? point . custom . hoverBorderColor : helpers . getValueAtIndexOrDefault ( dataset . pointHoverBorderColor , index , helpers . getHoverColor ( point . _model . borderColor ) ) ;
point . _model . borderWidth = point . custom && point . custom . hoverBorderWidth ? point . custom . hoverBorderWidth : helpers . getValueAtIndexOrDefault ( dataset . pointHoverBorderWidth , index , point . _model . borderWidth ) ;
} ,
removeHoverStyle : function ( point ) {
var dataset = this . chart . data . datasets [ point . _datasetIndex ] ;
var index = point . _index ;
point . _model . radius = point . custom && point . custom . radius ? point . custom . radius : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . radius , index , this . chart . options . elements . point . radius ) ;
point . _model . backgroundColor = point . custom && point . custom . backgroundColor ? point . custom . backgroundColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBackgroundColor , index , this . chart . options . elements . point . backgroundColor ) ;
point . _model . borderColor = point . custom && point . custom . borderColor ? point . custom . borderColor : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBorderColor , index , this . chart . options . elements . point . borderColor ) ;
point . _model . borderWidth = point . custom && point . custom . borderWidth ? point . custom . borderWidth : helpers . getValueAtIndexOrDefault ( this . getDataset ( ) . pointBorderWidth , index , this . chart . options . elements . point . borderWidth ) ;
}
} ) ;
} ;
} , { } ] , 21 : [ function ( require , module , exports ) {
/*global window: false */
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . global . animation = {
duration : 1000 ,
easing : "easeOutQuart" ,
onProgress : helpers . noop ,
onComplete : helpers . noop
} ;
Chart . Animation = Chart . Element . extend ( {
currentStep : null , // the current animation step
numSteps : 60 , // default number of steps
easing : "" , // the easing to use for this animation
render : null , // render function used by the animation service
onAnimationProgress : null , // user specified callback to fire on each step of the animation
onAnimationComplete : null // user specified callback to fire when the animation finishes
} ) ;
Chart . animationService = {
frameDuration : 17 ,
animations : [ ] ,
dropFrames : 0 ,
request : null ,
addAnimation : function ( chartInstance , animationObject , duration , lazy ) {
if ( ! lazy ) {
chartInstance . animating = true ;
}
for ( var index = 0 ; index < this . animations . length ; ++ index ) {
if ( this . animations [ index ] . chartInstance === chartInstance ) {
// replacing an in progress animation
this . animations [ index ] . animationObject = animationObject ;
return ;
}
}
this . animations . push ( {
chartInstance : chartInstance ,
animationObject : animationObject
} ) ;
// If there are no animations queued, manually kickstart a digest, for lack of a better word
if ( this . animations . length === 1 ) {
this . requestAnimationFrame ( ) ;
}
} ,
// Cancel the animation for a given chart instance
cancelAnimation : function ( chartInstance ) {
var index = helpers . findIndex ( this . animations , function ( animationWrapper ) {
return animationWrapper . chartInstance === chartInstance ;
} ) ;
if ( index !== - 1 ) {
this . animations . splice ( index , 1 ) ;
chartInstance . animating = false ;
}
} ,
requestAnimationFrame : function ( ) {
var me = this ;
if ( me . request === null ) {
// Skip animation frame requests until the active one is executed.
// This can happen when processing mouse events, e.g. 'mousemove'
// and 'mouseout' events will trigger multiple renders.
me . request = helpers . requestAnimFrame . call ( window , function ( ) {
me . request = null ;
me . startDigest ( ) ;
} ) ;
}
} ,
startDigest : function ( ) {
var startTime = Date . now ( ) ;
var framesToDrop = 0 ;
if ( this . dropFrames > 1 ) {
framesToDrop = Math . floor ( this . dropFrames ) ;
this . dropFrames = this . dropFrames % 1 ;
}
var i = 0 ;
while ( i < this . animations . length ) {
if ( this . animations [ i ] . animationObject . currentStep === null ) {
this . animations [ i ] . animationObject . currentStep = 0 ;
}
this . animations [ i ] . animationObject . currentStep += 1 + framesToDrop ;
if ( this . animations [ i ] . animationObject . currentStep > this . animations [ i ] . animationObject . numSteps ) {
this . animations [ i ] . animationObject . currentStep = this . animations [ i ] . animationObject . numSteps ;
}
this . animations [ i ] . animationObject . render ( this . animations [ i ] . chartInstance , this . animations [ i ] . animationObject ) ;
if ( this . animations [ i ] . animationObject . onAnimationProgress && this . animations [ i ] . animationObject . onAnimationProgress . call ) {
this . animations [ i ] . animationObject . onAnimationProgress . call ( this . animations [ i ] . chartInstance , this . animations [ i ] ) ;
}
if ( this . animations [ i ] . animationObject . currentStep === this . animations [ i ] . animationObject . numSteps ) {
if ( this . animations [ i ] . animationObject . onAnimationComplete && this . animations [ i ] . animationObject . onAnimationComplete . call ) {
this . animations [ i ] . animationObject . onAnimationComplete . call ( this . animations [ i ] . chartInstance , this . animations [ i ] ) ;
}
// executed the last frame. Remove the animation.
this . animations [ i ] . chartInstance . animating = false ;
this . animations . splice ( i , 1 ) ;
} else {
++ i ;
}
}
var endTime = Date . now ( ) ;
var dropFrames = ( endTime - startTime ) / this . frameDuration ;
this . dropFrames += dropFrames ;
// Do we have more stuff to animate?
if ( this . animations . length > 0 ) {
this . requestAnimationFrame ( ) ;
}
}
} ;
} ;
} , { } ] , 22 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
//Create a dictionary of chart types, to allow for extension of existing types
Chart . types = { } ;
//Store a reference to each instance - allowing us to globally resize chart instances on window resize.
//Destroy method on the chart will remove the instance of the chart from this reference.
Chart . instances = { } ;
// Controllers available for dataset visualization eg. bar, line, slice, etc.
Chart . controllers = { } ;
// The main controller of a chart
Chart . Controller = function ( instance ) {
this . chart = instance ;
this . config = instance . config ;
this . options = this . config . options = helpers . configMerge ( Chart . defaults . global , Chart . defaults [ this . config . type ] , this . config . options || { } ) ;
this . id = helpers . uid ( ) ;
Object . defineProperty ( this , 'data' , {
get : function ( ) {
return this . config . data ;
}
} ) ;
//Add the chart instance to the global namespace
Chart . instances [ this . id ] = this ;
if ( this . options . responsive ) {
// Silent resize before chart draws
this . resize ( true ) ;
}
this . initialize ( ) ;
return this ;
} ;
helpers . extend ( Chart . Controller . prototype , {
initialize : function initialize ( ) {
// Before init plugin notification
Chart . pluginService . notifyPlugins ( 'beforeInit' , [ this ] ) ;
this . bindEvents ( ) ;
// Make sure controllers are built first so that each dataset is bound to an axis before the scales
// are built
this . ensureScalesHaveIDs ( ) ;
this . buildOrUpdateControllers ( ) ;
this . buildScales ( ) ;
this . buildSurroundingItems ( ) ;
this . updateLayout ( ) ;
this . resetElements ( ) ;
this . initToolTip ( ) ;
this . update ( ) ;
// After init plugin notification
Chart . pluginService . notifyPlugins ( 'afterInit' , [ this ] ) ;
return this ;
} ,
clear : function clear ( ) {
helpers . clear ( this . chart ) ;
return this ;
} ,
stop : function stop ( ) {
// Stops any current animation loop occuring
Chart . animationService . cancelAnimation ( this ) ;
return this ;
} ,
resize : function resize ( silent ) {
var canvas = this . chart . canvas ;
var newWidth = helpers . getMaximumWidth ( this . chart . canvas ) ;
var newHeight = ( this . options . maintainAspectRatio && isNaN ( this . chart . aspectRatio ) === false && isFinite ( this . chart . aspectRatio ) && this . chart . aspectRatio !== 0 ) ? newWidth / this . chart . aspectRatio : helpers . getMaximumHeight ( this . chart . canvas ) ;
var sizeChanged = this . chart . width !== newWidth || this . chart . height !== newHeight ;
if ( ! sizeChanged )
return this ;
canvas . width = this . chart . width = newWidth ;
canvas . height = this . chart . height = newHeight ;
helpers . retinaScale ( this . chart ) ;
if ( ! silent ) {
this . stop ( ) ;
this . update ( this . options . responsiveAnimationDuration ) ;
}
return this ;
} ,
ensureScalesHaveIDs : function ensureScalesHaveIDs ( ) {
var defaultXAxisID = 'x-axis-' ;
var defaultYAxisID = 'y-axis-' ;
if ( this . options . scales ) {
if ( this . options . scales . xAxes && this . options . scales . xAxes . length ) {
helpers . each ( this . options . scales . xAxes , function ( xAxisOptions , index ) {
xAxisOptions . id = xAxisOptions . id || ( defaultXAxisID + index ) ;
} ) ;
}
if ( this . options . scales . yAxes && this . options . scales . yAxes . length ) {
// Build the y axes
helpers . each ( this . options . scales . yAxes , function ( yAxisOptions , index ) {
yAxisOptions . id = yAxisOptions . id || ( defaultYAxisID + index ) ;
} ) ;
}
}
} ,
buildScales : function buildScales ( ) {
// Map of scale ID to scale object so we can lookup later
this . scales = { } ;
// Build the x axes
if ( this . options . scales ) {
if ( this . options . scales . xAxes && this . options . scales . xAxes . length ) {
helpers . each ( this . options . scales . xAxes , function ( xAxisOptions , index ) {
var xType = helpers . getValueOrDefault ( xAxisOptions . type , 'category' ) ;
var ScaleClass = Chart . scaleService . getScaleConstructor ( xType ) ;
if ( ScaleClass ) {
var scale = new ScaleClass ( {
ctx : this . chart . ctx ,
options : xAxisOptions ,
chart : this ,
id : xAxisOptions . id
} ) ;
this . scales [ scale . id ] = scale ;
}
} , this ) ;
}
if ( this . options . scales . yAxes && this . options . scales . yAxes . length ) {
// Build the y axes
helpers . each ( this . options . scales . yAxes , function ( yAxisOptions , index ) {
var yType = helpers . getValueOrDefault ( yAxisOptions . type , 'linear' ) ;
var ScaleClass = Chart . scaleService . getScaleConstructor ( yType ) ;
if ( ScaleClass ) {
var scale = new ScaleClass ( {
ctx : this . chart . ctx ,
options : yAxisOptions ,
chart : this ,
id : yAxisOptions . id
} ) ;
this . scales [ scale . id ] = scale ;
}
} , this ) ;
}
}
if ( this . options . scale ) {
// Build radial axes
var ScaleClass = Chart . scaleService . getScaleConstructor ( this . options . scale . type ) ;
if ( ScaleClass ) {
var scale = new ScaleClass ( {
ctx : this . chart . ctx ,
options : this . options . scale ,
chart : this
} ) ;
this . scale = scale ;
this . scales . radialScale = scale ;
}
}
Chart . scaleService . addScalesToLayout ( this ) ;
} ,
buildSurroundingItems : function ( ) {
if ( this . options . title ) {
this . titleBlock = new Chart . Title ( {
ctx : this . chart . ctx ,
options : this . options . title ,
chart : this
} ) ;
Chart . layoutService . addBox ( this , this . titleBlock ) ;
}
if ( this . options . legend ) {
this . legend = new Chart . Legend ( {
ctx : this . chart . ctx ,
options : this . options . legend ,
chart : this
} ) ;
Chart . layoutService . addBox ( this , this . legend ) ;
}
} ,
updateLayout : function ( ) {
Chart . layoutService . update ( this , this . chart . width , this . chart . height ) ;
} ,
buildOrUpdateControllers : function buildOrUpdateControllers ( ) {
var types = [ ] ;
var newControllers = [ ] ;
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
var meta = this . getDatasetMeta ( datasetIndex ) ;
if ( ! meta . type ) {
meta . type = dataset . type || this . config . type ;
}
types . push ( meta . type ) ;
if ( meta . controller ) {
meta . controller . updateIndex ( datasetIndex ) ;
} else {
meta . controller = new Chart . controllers [ meta . type ] ( this , datasetIndex ) ;
newControllers . push ( meta . controller ) ;
}
} , this ) ;
if ( types . length > 1 ) {
for ( var i = 1 ; i < types . length ; i ++ ) {
if ( types [ i ] !== types [ i - 1 ] ) {
this . isCombo = true ;
break ;
}
}
}
return newControllers ;
} ,
resetElements : function resetElements ( ) {
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
this . getDatasetMeta ( datasetIndex ) . controller . reset ( ) ;
} , this ) ;
} ,
update : function update ( animationDuration , lazy ) {
Chart . pluginService . notifyPlugins ( 'beforeUpdate' , [ this ] ) ;
// In case the entire data object changed
this . tooltip . _data = this . data ;
// Make sure dataset controllers are updated and new controllers are reset
var newControllers = this . buildOrUpdateControllers ( ) ;
// Make sure all dataset controllers have correct meta data counts
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
this . getDatasetMeta ( datasetIndex ) . controller . buildOrUpdateElements ( ) ;
} , this ) ;
Chart . layoutService . update ( this , this . chart . width , this . chart . height ) ;
// Apply changes to the dataets that require the scales to have been calculated i.e BorderColor chages
Chart . pluginService . notifyPlugins ( 'afterScaleUpdate' , [ this ] ) ;
// Can only reset the new controllers after the scales have been updated
helpers . each ( newControllers , function ( controller ) {
controller . reset ( ) ;
} ) ;
// This will loop through any data and do the appropriate element update for the type
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
this . getDatasetMeta ( datasetIndex ) . controller . update ( ) ;
} , this ) ;
// Do this before render so that any plugins that need final scale updates can use it
Chart . pluginService . notifyPlugins ( 'afterUpdate' , [ this ] ) ;
this . render ( animationDuration , lazy ) ;
} ,
render : function render ( duration , lazy ) {
Chart . pluginService . notifyPlugins ( 'beforeRender' , [ this ] ) ;
if ( this . options . animation && ( ( typeof duration !== 'undefined' && duration !== 0 ) || ( typeof duration === 'undefined' && this . options . animation . duration !== 0 ) ) ) {
var animation = new Chart . Animation ( ) ;
animation . numSteps = ( duration || this . options . animation . duration ) / 16.66 ; //60 fps
animation . easing = this . options . animation . easing ;
// render function
animation . render = function ( chartInstance , animationObject ) {
var easingFunction = helpers . easingEffects [ animationObject . easing ] ;
var stepDecimal = animationObject . currentStep / animationObject . numSteps ;
var easeDecimal = easingFunction ( stepDecimal ) ;
chartInstance . draw ( easeDecimal , stepDecimal , animationObject . currentStep ) ;
} ;
// user events
animation . onAnimationProgress = this . options . animation . onProgress ;
animation . onAnimationComplete = this . options . animation . onComplete ;
Chart . animationService . addAnimation ( this , animation , duration , lazy ) ;
} else {
this . draw ( ) ;
if ( this . options . animation && this . options . animation . onComplete && this . options . animation . onComplete . call ) {
this . options . animation . onComplete . call ( this ) ;
}
}
return this ;
} ,
draw : function ( ease ) {
var easingDecimal = ease || 1 ;
this . clear ( ) ;
Chart . pluginService . notifyPlugins ( 'beforeDraw' , [ this , easingDecimal ] ) ;
// Draw all the scales
helpers . each ( this . boxes , function ( box ) {
box . draw ( this . chartArea ) ;
} , this ) ;
if ( this . scale ) {
this . scale . draw ( ) ;
}
// Clip out the chart area so that anything outside does not draw. This is necessary for zoom and pan to function
this . chart . ctx . save ( ) ;
this . chart . ctx . beginPath ( ) ;
this . chart . ctx . rect ( this . chartArea . left , this . chartArea . top , this . chartArea . right - this . chartArea . left , this . chartArea . bottom - this . chartArea . top ) ;
this . chart . ctx . clip ( ) ;
// Draw each dataset via its respective controller (reversed to support proper line stacking)
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
if ( this . isDatasetVisible ( datasetIndex ) ) {
this . getDatasetMeta ( datasetIndex ) . controller . draw ( ease ) ;
}
} , this , true ) ;
// Restore from the clipping operation
this . chart . ctx . restore ( ) ;
// Finally draw the tooltip
this . tooltip . transition ( easingDecimal ) . draw ( ) ;
Chart . pluginService . notifyPlugins ( 'afterDraw' , [ this , easingDecimal ] ) ;
} ,
// Get the single element that was clicked on
// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
getElementAtEvent : function ( e ) {
var eventPosition = helpers . getRelativePosition ( e , this . chart ) ;
var elementsArray = [ ] ;
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
if ( this . isDatasetVisible ( datasetIndex ) ) {
var meta = this . getDatasetMeta ( datasetIndex ) ;
helpers . each ( meta . data , function ( element , index ) {
if ( element . inRange ( eventPosition . x , eventPosition . y ) ) {
elementsArray . push ( element ) ;
return elementsArray ;
}
} ) ;
}
} , this ) ;
return elementsArray ;
} ,
getElementsAtEvent : function ( e ) {
var eventPosition = helpers . getRelativePosition ( e , this . chart ) ;
var elementsArray = [ ] ;
var found = ( function ( ) {
if ( this . data . datasets ) {
for ( var i = 0 ; i < this . data . datasets . length ; i ++ ) {
var meta = this . getDatasetMeta ( i ) ;
if ( this . isDatasetVisible ( i ) ) {
for ( var j = 0 ; j < meta . data . length ; j ++ ) {
if ( meta . data [ j ] . inRange ( eventPosition . x , eventPosition . y ) ) {
return meta . data [ j ] ;
}
}
}
}
}
} ) . call ( this ) ;
if ( ! found ) {
return elementsArray ;
}
helpers . each ( this . data . datasets , function ( dataset , datasetIndex ) {
if ( this . isDatasetVisible ( datasetIndex ) ) {
var meta = this . getDatasetMeta ( datasetIndex ) ;
elementsArray . push ( meta . data [ found . _index ] ) ;
}
} , this ) ;
return elementsArray ;
} ,
getDatasetAtEvent : function ( e ) {
var elementsArray = this . getElementAtEvent ( e ) ;
if ( elementsArray . length > 0 ) {
elementsArray = this . getDatasetMeta ( elementsArray [ 0 ] . _datasetIndex ) . data ;
}
return elementsArray ;
} ,
getDatasetMeta : function ( datasetIndex ) {
var dataset = this . data . datasets [ datasetIndex ] ;
if ( ! dataset . _meta ) {
dataset . _meta = { } ;
}
var meta = dataset . _meta [ this . id ] ;
if ( ! meta ) {
meta = dataset . _meta [ this . id ] = {
type : null ,
data : [ ] ,
dataset : null ,
controller : null ,
hidden : null , // See isDatasetVisible() comment
xAxisID : null ,
yAxisID : null
} ;
}
return meta ;
} ,
getVisibleDatasetCount : function ( ) {
var count = 0 ;
for ( var i = 0 , ilen = this . data . datasets . length ; i < ilen ; ++ i ) {
if ( this . isDatasetVisible ( i ) ) {
count ++ ;
}
}
return count ;
} ,
isDatasetVisible : function ( datasetIndex ) {
var meta = this . getDatasetMeta ( datasetIndex ) ;
// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
return typeof meta . hidden === 'boolean' ? ! meta . hidden : ! this . data . datasets [ datasetIndex ] . hidden ;
} ,
generateLegend : function generateLegend ( ) {
return this . options . legendCallback ( this ) ;
} ,
destroy : function destroy ( ) {
this . clear ( ) ;
helpers . unbindEvents ( this , this . events ) ;
helpers . removeResizeListener ( this . chart . canvas . parentNode ) ;
// Reset canvas height/width attributes
var canvas = this . chart . canvas ;
canvas . width = this . chart . width ;
canvas . height = this . chart . height ;
// if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here
if ( this . chart . originalDevicePixelRatio !== undefined ) {
this . chart . ctx . scale ( 1 / this . chart . originalDevicePixelRatio , 1 / this . chart . originalDevicePixelRatio ) ;
}
// Reset to the old style since it may have been changed by the device pixel ratio changes
canvas . style . width = this . chart . originalCanvasStyleWidth ;
canvas . style . height = this . chart . originalCanvasStyleHeight ;
Chart . pluginService . notifyPlugins ( 'destroy' , [ this ] ) ;
delete Chart . instances [ this . id ] ;
} ,
toBase64Image : function toBase64Image ( ) {
return this . chart . canvas . toDataURL . apply ( this . chart . canvas , arguments ) ;
} ,
initToolTip : function initToolTip ( ) {
this . tooltip = new Chart . Tooltip ( {
_chart : this . chart ,
_chartInstance : this ,
_data : this . data ,
_options : this . options
} , this ) ;
} ,
bindEvents : function bindEvents ( ) {
helpers . bindEvents ( this , this . options . events , function ( evt ) {
this . eventHandler ( evt ) ;
} ) ;
} ,
eventHandler : function eventHandler ( e ) {
this . lastActive = this . lastActive || [ ] ;
this . lastTooltipActive = this . lastTooltipActive || [ ] ;
// Find Active Elements for hover and tooltips
if ( e . type === 'mouseout' ) {
this . active = [ ] ;
this . tooltipActive = [ ] ;
} else {
var _this = this ;
var getItemsForMode = function ( mode ) {
switch ( mode ) {
case 'single' :
return _this . getElementAtEvent ( e ) ;
case 'label' :
return _this . getElementsAtEvent ( e ) ;
case 'dataset' :
return _this . getDatasetAtEvent ( e ) ;
default :
return e ;
}
} ;
this . active = getItemsForMode ( this . options . hover . mode ) ;
this . tooltipActive = getItemsForMode ( this . options . tooltips . mode ) ;
}
// On Hover hook
if ( this . options . hover . onHover ) {
this . options . hover . onHover . call ( this , this . active ) ;
}
if ( e . type === 'mouseup' || e . type === 'click' ) {
if ( this . options . onClick ) {
this . options . onClick . call ( this , e , this . active ) ;
}
if ( this . legend && this . legend . handleEvent ) {
this . legend . handleEvent ( e ) ;
}
}
// Remove styling for last active (even if it may still be active)
if ( this . lastActive . length ) {
switch ( this . options . hover . mode ) {
case 'single' :
this . getDatasetMeta ( this . lastActive [ 0 ] . _datasetIndex ) . controller . removeHoverStyle ( this . lastActive [ 0 ] , this . lastActive [ 0 ] . _datasetIndex , this . lastActive [ 0 ] . _index ) ;
break ;
case 'label' :
case 'dataset' :
for ( var i = 0 ; i < this . lastActive . length ; i ++ ) {
if ( this . lastActive [ i ] )
this . getDatasetMeta ( this . lastActive [ i ] . _datasetIndex ) . controller . removeHoverStyle ( this . lastActive [ i ] , this . lastActive [ i ] . _datasetIndex , this . lastActive [ i ] . _index ) ;
}
break ;
default :
// Don't change anything
}
}
// Built in hover styling
if ( this . active . length && this . options . hover . mode ) {
switch ( this . options . hover . mode ) {
case 'single' :
this . getDatasetMeta ( this . active [ 0 ] . _datasetIndex ) . controller . setHoverStyle ( this . active [ 0 ] ) ;
break ;
case 'label' :
case 'dataset' :
for ( var j = 0 ; j < this . active . length ; j ++ ) {
if ( this . active [ j ] )
this . getDatasetMeta ( this . active [ j ] . _datasetIndex ) . controller . setHoverStyle ( this . active [ j ] ) ;
}
break ;
default :
// Don't change anything
}
}
// Built in Tooltips
if ( this . options . tooltips . enabled || this . options . tooltips . custom ) {
// The usual updates
this . tooltip . initialize ( ) ;
this . tooltip . _active = this . tooltipActive ;
this . tooltip . update ( true ) ;
}
// Hover animations
this . tooltip . pivot ( ) ;
if ( ! this . animating ) {
var changed ;
helpers . each ( this . active , function ( element , index ) {
if ( element !== this . lastActive [ index ] ) {
changed = true ;
}
} , this ) ;
helpers . each ( this . tooltipActive , function ( element , index ) {
if ( element !== this . lastTooltipActive [ index ] ) {
changed = true ;
}
} , this ) ;
// If entering, leaving, or changing elements, animate the change via pivot
if ( ( this . lastActive . length !== this . active . length ) ||
( this . lastTooltipActive . length !== this . tooltipActive . length ) ||
changed ) {
this . stop ( ) ;
if ( this . options . tooltips . enabled || this . options . tooltips . custom ) {
this . tooltip . update ( true ) ;
}
// We only need to render at this point. Updating will cause scales to be recomputed generating flicker & using more
// memory than necessary.
this . render ( this . options . hover . animationDuration , true ) ;
}
}
// Remember Last Actives
this . lastActive = this . active ;
this . lastTooltipActive = this . tooltipActive ;
return this ;
}
} ) ;
} ;
} , { } ] , 23 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var noop = helpers . noop ;
// Base class for all dataset controllers (line, bar, etc)
Chart . DatasetController = function ( chart , datasetIndex ) {
this . initialize . call ( this , chart , datasetIndex ) ;
} ;
helpers . extend ( Chart . DatasetController . prototype , {
initialize : function ( chart , datasetIndex ) {
this . chart = chart ;
this . index = datasetIndex ;
this . linkScales ( ) ;
this . addElements ( ) ;
} ,
updateIndex : function ( datasetIndex ) {
this . index = datasetIndex ;
} ,
linkScales : function ( ) {
var meta = this . getMeta ( ) ;
var dataset = this . getDataset ( ) ;
if ( meta . xAxisID === null ) {
meta . xAxisID = dataset . xAxisID || this . chart . options . scales . xAxes [ 0 ] . id ;
}
if ( meta . yAxisID === null ) {
meta . yAxisID = dataset . yAxisID || this . chart . options . scales . yAxes [ 0 ] . id ;
}
} ,
getDataset : function ( ) {
return this . chart . data . datasets [ this . index ] ;
} ,
getMeta : function ( ) {
return this . chart . getDatasetMeta ( this . index ) ;
} ,
getScaleForId : function ( scaleID ) {
return this . chart . scales [ scaleID ] ;
} ,
reset : function ( ) {
this . update ( true ) ;
} ,
buildOrUpdateElements : function buildOrUpdateElements ( ) {
// Handle the number of data points changing
var meta = this . getMeta ( ) ,
md = meta . data ,
numData = this . getDataset ( ) . data . length ,
numMetaData = md . length ;
// Make sure that we handle number of datapoints changing
if ( numData < numMetaData ) {
// Remove excess bars for data points that have been removed
md . splice ( numData , numMetaData - numData ) ;
} else if ( numData > numMetaData ) {
// Add new elements
for ( var index = numMetaData ; index < numData ; ++ index ) {
this . addElementAndReset ( index ) ;
}
}
} ,
// Controllers should implement the following
addElements : noop ,
addElementAndReset : noop ,
draw : noop ,
removeHoverStyle : noop ,
setHoverStyle : noop ,
update : noop
} ) ;
Chart . DatasetController . extend = helpers . inherits ;
} ;
} , { } ] , 24 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . elements = { } ;
Chart . Element = function ( configuration ) {
helpers . extend ( this , configuration ) ;
this . initialize . apply ( this , arguments ) ;
} ;
helpers . extend ( Chart . Element . prototype , {
initialize : function ( ) {
this . hidden = false ;
} ,
pivot : function ( ) {
if ( ! this . _view ) {
this . _view = helpers . clone ( this . _model ) ;
}
this . _start = helpers . clone ( this . _view ) ;
return this ;
} ,
transition : function ( ease ) {
if ( ! this . _view ) {
this . _view = helpers . clone ( this . _model ) ;
}
// No animation -> No Transition
if ( ease === 1 ) {
this . _view = this . _model ;
this . _start = null ;
return this ;
}
if ( ! this . _start ) {
this . pivot ( ) ;
}
helpers . each ( this . _model , function ( value , key ) {
if ( key [ 0 ] === '_' || ! this . _model . hasOwnProperty ( key ) ) {
// Only non-underscored properties
}
// Init if doesn't exist
else if ( ! this . _view . hasOwnProperty ( key ) ) {
if ( typeof value === 'number' && ! isNaN ( this . _view [ key ] ) ) {
this . _view [ key ] = value * ease ;
} else {
this . _view [ key ] = value ;
}
}
// No unnecessary computations
else if ( value === this . _view [ key ] ) {
// It's the same! Woohoo!
}
// Color transitions if possible
else if ( typeof value === 'string' ) {
try {
var color = helpers . color ( this . _start [ key ] ) . mix ( helpers . color ( this . _model [ key ] ) , ease ) ;
this . _view [ key ] = color . rgbString ( ) ;
} catch ( err ) {
this . _view [ key ] = value ;
}
}
// Number transitions
else if ( typeof value === 'number' ) {
var startVal = this . _start [ key ] !== undefined && isNaN ( this . _start [ key ] ) === false ? this . _start [ key ] : 0 ;
this . _view [ key ] = ( ( this . _model [ key ] - startVal ) * ease ) + startVal ;
}
// Everything else
else {
this . _view [ key ] = value ;
}
} , this ) ;
return this ;
} ,
tooltipPosition : function ( ) {
return {
x : this . _model . x ,
y : this . _model . y
} ;
} ,
hasValue : function ( ) {
return helpers . isNumber ( this . _model . x ) && helpers . isNumber ( this . _model . y ) ;
}
} ) ;
Chart . Element . extend = helpers . inherits ;
} ;
} , { } ] , 25 : [ function ( require , module , exports ) {
/*global window: false */
/*global document: false */
"use strict" ;
var color = require ( 'chartjs-color' ) ;
module . exports = function ( Chart ) {
//Global Chart helpers object for utility methods and classes
var helpers = Chart . helpers = { } ;
//-- Basic js utility methods
helpers . each = function ( loopable , callback , self , reverse ) {
// Check to see if null or undefined firstly.
var i , len ;
if ( helpers . isArray ( loopable ) ) {
len = loopable . length ;
if ( reverse ) {
for ( i = len - 1 ; i >= 0 ; i -- ) {
callback . call ( self , loopable [ i ] , i ) ;
}
} else {
for ( i = 0 ; i < len ; i ++ ) {
callback . call ( self , loopable [ i ] , i ) ;
}
}
} else if ( typeof loopable === 'object' ) {
var keys = Object . keys ( loopable ) ;
len = keys . length ;
for ( i = 0 ; i < len ; i ++ ) {
callback . call ( self , loopable [ keys [ i ] ] , keys [ i ] ) ;
}
}
} ;
helpers . clone = function ( obj ) {
var objClone = { } ;
helpers . each ( obj , function ( value , key ) {
if ( obj . hasOwnProperty ( key ) ) {
if ( helpers . isArray ( value ) ) {
objClone [ key ] = value . slice ( 0 ) ;
} else if ( typeof value === 'object' && value !== null ) {
objClone [ key ] = helpers . clone ( value ) ;
} else {
objClone [ key ] = value ;
}
}
} ) ;
return objClone ;
} ;
helpers . extend = function ( base ) {
var len = arguments . length ;
var additionalArgs = [ ] ;
for ( var i = 1 ; i < len ; i ++ ) {
additionalArgs . push ( arguments [ i ] ) ;
}
helpers . each ( additionalArgs , function ( extensionObject ) {
helpers . each ( extensionObject , function ( value , key ) {
if ( extensionObject . hasOwnProperty ( key ) ) {
base [ key ] = value ;
}
} ) ;
} ) ;
return base ;
} ;
// Need a special merge function to chart configs since they are now grouped
helpers . configMerge = function ( _base ) {
var base = helpers . clone ( _base ) ;
helpers . each ( Array . prototype . slice . call ( arguments , 1 ) , function ( extension ) {
helpers . each ( extension , function ( value , key ) {
if ( extension . hasOwnProperty ( key ) ) {
if ( key === 'scales' ) {
// Scale config merging is complex. Add out own function here for that
base [ key ] = helpers . scaleMerge ( base . hasOwnProperty ( key ) ? base [ key ] : { } , value ) ;
} else if ( key === 'scale' ) {
// Used in polar area & radar charts since there is only one scale
base [ key ] = helpers . configMerge ( base . hasOwnProperty ( key ) ? base [ key ] : { } , Chart . scaleService . getScaleDefaults ( value . type ) , value ) ;
} else if ( base . hasOwnProperty ( key ) && helpers . isArray ( base [ key ] ) && helpers . isArray ( value ) ) {
// In this case we have an array of objects replacing another array. Rather than doing a strict replace,
// merge. This allows easy scale option merging
var baseArray = base [ key ] ;
helpers . each ( value , function ( valueObj , index ) {
if ( index < baseArray . length ) {
if ( typeof baseArray [ index ] === 'object' && baseArray [ index ] !== null && typeof valueObj === 'object' && valueObj !== null ) {
// Two objects are coming together. Do a merge of them.
baseArray [ index ] = helpers . configMerge ( baseArray [ index ] , valueObj ) ;
} else {
// Just overwrite in this case since there is nothing to merge
baseArray [ index ] = valueObj ;
}
} else {
baseArray . push ( valueObj ) ; // nothing to merge
}
} ) ;
} else if ( base . hasOwnProperty ( key ) && typeof base [ key ] === "object" && base [ key ] !== null && typeof value === "object" ) {
// If we are overwriting an object with an object, do a merge of the properties.
base [ key ] = helpers . configMerge ( base [ key ] , value ) ;
} else {
// can just overwrite the value in this case
base [ key ] = value ;
}
}
} ) ;
} ) ;
return base ;
} ;
helpers . extendDeep = function ( _base ) {
return _extendDeep . apply ( this , arguments ) ;
function _extendDeep ( dst ) {
helpers . each ( arguments , function ( obj ) {
if ( obj !== dst ) {
helpers . each ( obj , function ( value , key ) {
if ( dst [ key ] && dst [ key ] . constructor && dst [ key ] . constructor === Object ) {
_extendDeep ( dst [ key ] , value ) ;
} else {
dst [ key ] = value ;
}
} ) ;
}
} ) ;
return dst ;
}
} ;
helpers . scaleMerge = function ( _base , extension ) {
var base = helpers . clone ( _base ) ;
helpers . each ( extension , function ( value , key ) {
if ( extension . hasOwnProperty ( key ) ) {
if ( key === 'xAxes' || key === 'yAxes' ) {
// These properties are arrays of items
if ( base . hasOwnProperty ( key ) ) {
helpers . each ( value , function ( valueObj , index ) {
var axisType = helpers . getValueOrDefault ( valueObj . type , key === 'xAxes' ? 'category' : 'linear' ) ;
var axisDefaults = Chart . scaleService . getScaleDefaults ( axisType ) ;
if ( index >= base [ key ] . length || ! base [ key ] [ index ] . type ) {
base [ key ] . push ( helpers . configMerge ( axisDefaults , valueObj ) ) ;
} else if ( valueObj . type && valueObj . type !== base [ key ] [ index ] . type ) {
// Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults
base [ key ] [ index ] = helpers . configMerge ( base [ key ] [ index ] , axisDefaults , valueObj ) ;
} else {
// Type is the same
base [ key ] [ index ] = helpers . configMerge ( base [ key ] [ index ] , valueObj ) ;
}
} ) ;
} else {
base [ key ] = [ ] ;
helpers . each ( value , function ( valueObj ) {
var axisType = helpers . getValueOrDefault ( valueObj . type , key === 'xAxes' ? 'category' : 'linear' ) ;
base [ key ] . push ( helpers . configMerge ( Chart . scaleService . getScaleDefaults ( axisType ) , valueObj ) ) ;
} ) ;
}
} else if ( base . hasOwnProperty ( key ) && typeof base [ key ] === "object" && base [ key ] !== null && typeof value === "object" ) {
// If we are overwriting an object with an object, do a merge of the properties.
base [ key ] = helpers . configMerge ( base [ key ] , value ) ;
} else {
// can just overwrite the value in this case
base [ key ] = value ;
}
}
} ) ;
return base ;
} ;
helpers . getValueAtIndexOrDefault = function ( value , index , defaultValue ) {
if ( value === undefined || value === null ) {
return defaultValue ;
}
if ( helpers . isArray ( value ) ) {
return index < value . length ? value [ index ] : defaultValue ;
}
return value ;
} ;
helpers . getValueOrDefault = function ( value , defaultValue ) {
return value === undefined ? defaultValue : value ;
} ;
helpers . indexOf = function ( arrayToSearch , item ) {
if ( Array . prototype . indexOf ) {
return arrayToSearch . indexOf ( item ) ;
} else {
for ( var i = 0 ; i < arrayToSearch . length ; i ++ ) {
if ( arrayToSearch [ i ] === item )
return i ;
}
return - 1 ;
}
} ;
helpers . where = function ( collection , filterCallback ) {
var filtered = [ ] ;
helpers . each ( collection , function ( item ) {
if ( filterCallback ( item ) ) {
filtered . push ( item ) ;
}
} ) ;
return filtered ;
} ;
helpers . findIndex = function ( arrayToSearch , callback , thisArg ) {
var index = - 1 ;
if ( Array . prototype . findIndex ) {
index = arrayToSearch . findIndex ( callback , thisArg ) ;
} else {
for ( var i = 0 ; i < arrayToSearch . length ; ++ i ) {
thisArg = thisArg !== undefined ? thisArg : arrayToSearch ;
if ( callback . call ( thisArg , arrayToSearch [ i ] , i , arrayToSearch ) ) {
index = i ;
break ;
}
}
}
return index ;
} ;
helpers . findNextWhere = function ( arrayToSearch , filterCallback , startIndex ) {
// Default to start of the array
if ( startIndex === undefined || startIndex === null ) {
startIndex = - 1 ;
}
for ( var i = startIndex + 1 ; i < arrayToSearch . length ; i ++ ) {
var currentItem = arrayToSearch [ i ] ;
if ( filterCallback ( currentItem ) ) {
return currentItem ;
}
}
} ;
helpers . findPreviousWhere = function ( arrayToSearch , filterCallback , startIndex ) {
// Default to end of the array
if ( startIndex === undefined || startIndex === null ) {
startIndex = arrayToSearch . length ;
}
for ( var i = startIndex - 1 ; i >= 0 ; i -- ) {
var currentItem = arrayToSearch [ i ] ;
if ( filterCallback ( currentItem ) ) {
return currentItem ;
}
}
} ;
helpers . inherits = function ( extensions ) {
//Basic javascript inheritance based on the model created in Backbone.js
var parent = this ;
var ChartElement = ( extensions && extensions . hasOwnProperty ( "constructor" ) ) ? extensions . constructor : function ( ) {
return parent . apply ( this , arguments ) ;
} ;
var Surrogate = function ( ) {
this . constructor = ChartElement ;
} ;
Surrogate . prototype = parent . prototype ;
ChartElement . prototype = new Surrogate ( ) ;
ChartElement . extend = helpers . inherits ;
if ( extensions ) {
helpers . extend ( ChartElement . prototype , extensions ) ;
}
ChartElement . _ _super _ _ = parent . prototype ;
return ChartElement ;
} ;
helpers . noop = function ( ) { } ;
helpers . uid = ( function ( ) {
var id = 0 ;
return function ( ) {
return id ++ ;
} ;
} ) ( ) ;
helpers . warn = function ( str ) {
//Method for warning of errors
if ( console && typeof console . warn === "function" ) {
console . warn ( str ) ;
}
} ;
//-- Math methods
helpers . isNumber = function ( n ) {
return ! isNaN ( parseFloat ( n ) ) && isFinite ( n ) ;
} ;
helpers . almostEquals = function ( x , y , epsilon ) {
return Math . abs ( x - y ) < epsilon ;
} ;
helpers . max = function ( array ) {
return array . reduce ( function ( max , value ) {
if ( ! isNaN ( value ) ) {
return Math . max ( max , value ) ;
} else {
return max ;
}
} , Number . NEGATIVE _INFINITY ) ;
} ;
helpers . min = function ( array ) {
return array . reduce ( function ( min , value ) {
if ( ! isNaN ( value ) ) {
return Math . min ( min , value ) ;
} else {
return min ;
}
} , Number . POSITIVE _INFINITY ) ;
} ;
helpers . sign = function ( x ) {
if ( Math . sign ) {
return Math . sign ( x ) ;
} else {
x = + x ; // convert to a number
if ( x === 0 || isNaN ( x ) ) {
return x ;
}
return x > 0 ? 1 : - 1 ;
}
} ;
helpers . log10 = function ( x ) {
if ( Math . log10 ) {
return Math . log10 ( x ) ;
} else {
return Math . log ( x ) / Math . LN10 ;
}
} ;
helpers . toRadians = function ( degrees ) {
return degrees * ( Math . PI / 180 ) ;
} ;
helpers . toDegrees = function ( radians ) {
return radians * ( 180 / Math . PI ) ;
} ;
// Gets the angle from vertical upright to the point about a centre.
helpers . getAngleFromPoint = function ( centrePoint , anglePoint ) {
var distanceFromXCenter = anglePoint . x - centrePoint . x ,
distanceFromYCenter = anglePoint . y - centrePoint . y ,
radialDistanceFromCenter = Math . sqrt ( distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter ) ;
var angle = Math . atan2 ( distanceFromYCenter , distanceFromXCenter ) ;
if ( angle < ( - 0.5 * Math . PI ) ) {
angle += 2.0 * Math . PI ; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
}
return {
angle : angle ,
distance : radialDistanceFromCenter
} ;
} ;
helpers . aliasPixel = function ( pixelWidth ) {
return ( pixelWidth % 2 === 0 ) ? 0 : 0.5 ;
} ;
helpers . splineCurve = function ( firstPoint , middlePoint , afterPoint , t ) {
//Props to Rob Spencer at scaled innovation for his post on splining between points
//http://scaledinnovation.com/analytics/splines/aboutSplines.html
// This function must also respect "skipped" points
var previous = firstPoint . skip ? middlePoint : firstPoint ,
current = middlePoint ,
next = afterPoint . skip ? middlePoint : afterPoint ;
var d01 = Math . sqrt ( Math . pow ( current . x - previous . x , 2 ) + Math . pow ( current . y - previous . y , 2 ) ) ;
var d12 = Math . sqrt ( Math . pow ( next . x - current . x , 2 ) + Math . pow ( next . y - current . y , 2 ) ) ;
var s01 = d01 / ( d01 + d12 ) ;
var s12 = d12 / ( d01 + d12 ) ;
// If all points are the same, s01 & s02 will be inf
s01 = isNaN ( s01 ) ? 0 : s01 ;
s12 = isNaN ( s12 ) ? 0 : s12 ;
var fa = t * s01 ; // scaling factor for triangle Ta
var fb = t * s12 ;
return {
previous : {
x : current . x - fa * ( next . x - previous . x ) ,
y : current . y - fa * ( next . y - previous . y )
} ,
next : {
x : current . x + fb * ( next . x - previous . x ) ,
y : current . y + fb * ( next . y - previous . y )
}
} ;
} ;
helpers . nextItem = function ( collection , index , loop ) {
if ( loop ) {
return index >= collection . length - 1 ? collection [ 0 ] : collection [ index + 1 ] ;
}
return index >= collection . length - 1 ? collection [ collection . length - 1 ] : collection [ index + 1 ] ;
} ;
helpers . previousItem = function ( collection , index , loop ) {
if ( loop ) {
return index <= 0 ? collection [ collection . length - 1 ] : collection [ index - 1 ] ;
}
return index <= 0 ? collection [ 0 ] : collection [ index - 1 ] ;
} ;
// Implementation of the nice number algorithm used in determining where axis labels will go
helpers . niceNum = function ( range , round ) {
var exponent = Math . floor ( helpers . log10 ( range ) ) ;
var fraction = range / Math . pow ( 10 , exponent ) ;
var niceFraction ;
if ( round ) {
if ( fraction < 1.5 ) {
niceFraction = 1 ;
} else if ( fraction < 3 ) {
niceFraction = 2 ;
} else if ( fraction < 7 ) {
niceFraction = 5 ;
} else {
niceFraction = 10 ;
}
} else {
if ( fraction <= 1.0 ) {
niceFraction = 1 ;
} else if ( fraction <= 2 ) {
niceFraction = 2 ;
} else if ( fraction <= 5 ) {
niceFraction = 5 ;
} else {
niceFraction = 10 ;
}
}
return niceFraction * Math . pow ( 10 , exponent ) ;
} ;
//Easing functions adapted from Robert Penner's easing equations
//http://www.robertpenner.com/easing/
var easingEffects = helpers . easingEffects = {
linear : function ( t ) {
return t ;
} ,
easeInQuad : function ( t ) {
return t * t ;
} ,
easeOutQuad : function ( t ) {
return - 1 * t * ( t - 2 ) ;
} ,
easeInOutQuad : function ( t ) {
if ( ( t /= 1 / 2 ) < 1 ) {
return 1 / 2 * t * t ;
}
return - 1 / 2 * ( ( -- t ) * ( t - 2 ) - 1 ) ;
} ,
easeInCubic : function ( t ) {
return t * t * t ;
} ,
easeOutCubic : function ( t ) {
return 1 * ( ( t = t / 1 - 1 ) * t * t + 1 ) ;
} ,
easeInOutCubic : function ( t ) {
if ( ( t /= 1 / 2 ) < 1 ) {
return 1 / 2 * t * t * t ;
}
return 1 / 2 * ( ( t -= 2 ) * t * t + 2 ) ;
} ,
easeInQuart : function ( t ) {
return t * t * t * t ;
} ,
easeOutQuart : function ( t ) {
return - 1 * ( ( t = t / 1 - 1 ) * t * t * t - 1 ) ;
} ,
easeInOutQuart : function ( t ) {
if ( ( t /= 1 / 2 ) < 1 ) {
return 1 / 2 * t * t * t * t ;
}
return - 1 / 2 * ( ( t -= 2 ) * t * t * t - 2 ) ;
} ,
easeInQuint : function ( t ) {
return 1 * ( t /= 1 ) * t * t * t * t ;
} ,
easeOutQuint : function ( t ) {
return 1 * ( ( t = t / 1 - 1 ) * t * t * t * t + 1 ) ;
} ,
easeInOutQuint : function ( t ) {
if ( ( t /= 1 / 2 ) < 1 ) {
return 1 / 2 * t * t * t * t * t ;
}
return 1 / 2 * ( ( t -= 2 ) * t * t * t * t + 2 ) ;
} ,
easeInSine : function ( t ) {
return - 1 * Math . cos ( t / 1 * ( Math . PI / 2 ) ) + 1 ;
} ,
easeOutSine : function ( t ) {
return 1 * Math . sin ( t / 1 * ( Math . PI / 2 ) ) ;
} ,
easeInOutSine : function ( t ) {
return - 1 / 2 * ( Math . cos ( Math . PI * t / 1 ) - 1 ) ;
} ,
easeInExpo : function ( t ) {
return ( t === 0 ) ? 1 : 1 * Math . pow ( 2 , 10 * ( t / 1 - 1 ) ) ;
} ,
easeOutExpo : function ( t ) {
return ( t === 1 ) ? 1 : 1 * ( - Math . pow ( 2 , - 10 * t / 1 ) + 1 ) ;
} ,
easeInOutExpo : function ( t ) {
if ( t === 0 ) {
return 0 ;
}
if ( t === 1 ) {
return 1 ;
}
if ( ( t /= 1 / 2 ) < 1 ) {
return 1 / 2 * Math . pow ( 2 , 10 * ( t - 1 ) ) ;
}
return 1 / 2 * ( - Math . pow ( 2 , - 10 * -- t ) + 2 ) ;
} ,
easeInCirc : function ( t ) {
if ( t >= 1 ) {
return t ;
}
return - 1 * ( Math . sqrt ( 1 - ( t /= 1 ) * t ) - 1 ) ;
} ,
easeOutCirc : function ( t ) {
return 1 * Math . sqrt ( 1 - ( t = t / 1 - 1 ) * t ) ;
} ,
easeInOutCirc : function ( t ) {
if ( ( t /= 1 / 2 ) < 1 ) {
return - 1 / 2 * ( Math . sqrt ( 1 - t * t ) - 1 ) ;
}
return 1 / 2 * ( Math . sqrt ( 1 - ( t -= 2 ) * t ) + 1 ) ;
} ,
easeInElastic : function ( t ) {
var s = 1.70158 ;
var p = 0 ;
var a = 1 ;
if ( t === 0 ) {
return 0 ;
}
if ( ( t /= 1 ) === 1 ) {
return 1 ;
}
if ( ! p ) {
p = 1 * 0.3 ;
}
if ( a < Math . abs ( 1 ) ) {
a = 1 ;
s = p / 4 ;
} else {
s = p / ( 2 * Math . PI ) * Math . asin ( 1 / a ) ;
}
return - ( a * Math . pow ( 2 , 10 * ( t -= 1 ) ) * Math . sin ( ( t * 1 - s ) * ( 2 * Math . PI ) / p ) ) ;
} ,
easeOutElastic : function ( t ) {
var s = 1.70158 ;
var p = 0 ;
var a = 1 ;
if ( t === 0 ) {
return 0 ;
}
if ( ( t /= 1 ) === 1 ) {
return 1 ;
}
if ( ! p ) {
p = 1 * 0.3 ;
}
if ( a < Math . abs ( 1 ) ) {
a = 1 ;
s = p / 4 ;
} else {
s = p / ( 2 * Math . PI ) * Math . asin ( 1 / a ) ;
}
return a * Math . pow ( 2 , - 10 * t ) * Math . sin ( ( t * 1 - s ) * ( 2 * Math . PI ) / p ) + 1 ;
} ,
easeInOutElastic : function ( t ) {
var s = 1.70158 ;
var p = 0 ;
var a = 1 ;
if ( t === 0 ) {
return 0 ;
}
if ( ( t /= 1 / 2 ) === 2 ) {
return 1 ;
}
if ( ! p ) {
p = 1 * ( 0.3 * 1.5 ) ;
}
if ( a < Math . abs ( 1 ) ) {
a = 1 ;
s = p / 4 ;
} else {
s = p / ( 2 * Math . PI ) * Math . asin ( 1 / a ) ;
}
if ( t < 1 ) {
return - 0.5 * ( a * Math . pow ( 2 , 10 * ( t -= 1 ) ) * Math . sin ( ( t * 1 - s ) * ( 2 * Math . PI ) / p ) ) ;
}
return a * Math . pow ( 2 , - 10 * ( t -= 1 ) ) * Math . sin ( ( t * 1 - s ) * ( 2 * Math . PI ) / p ) * 0.5 + 1 ;
} ,
easeInBack : function ( t ) {
var s = 1.70158 ;
return 1 * ( t /= 1 ) * t * ( ( s + 1 ) * t - s ) ;
} ,
easeOutBack : function ( t ) {
var s = 1.70158 ;
return 1 * ( ( t = t / 1 - 1 ) * t * ( ( s + 1 ) * t + s ) + 1 ) ;
} ,
easeInOutBack : function ( t ) {
var s = 1.70158 ;
if ( ( t /= 1 / 2 ) < 1 ) {
return 1 / 2 * ( t * t * ( ( ( s *= ( 1.525 ) ) + 1 ) * t - s ) ) ;
}
return 1 / 2 * ( ( t -= 2 ) * t * ( ( ( s *= ( 1.525 ) ) + 1 ) * t + s ) + 2 ) ;
} ,
easeInBounce : function ( t ) {
return 1 - easingEffects . easeOutBounce ( 1 - t ) ;
} ,
easeOutBounce : function ( t ) {
if ( ( t /= 1 ) < ( 1 / 2.75 ) ) {
return 1 * ( 7.5625 * t * t ) ;
} else if ( t < ( 2 / 2.75 ) ) {
return 1 * ( 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75 ) ;
} else if ( t < ( 2.5 / 2.75 ) ) {
return 1 * ( 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375 ) ;
} else {
return 1 * ( 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375 ) ;
}
} ,
easeInOutBounce : function ( t ) {
if ( t < 1 / 2 ) {
return easingEffects . easeInBounce ( t * 2 ) * 0.5 ;
}
return easingEffects . easeOutBounce ( t * 2 - 1 ) * 0.5 + 1 * 0.5 ;
}
} ;
//Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
helpers . requestAnimFrame = ( function ( ) {
return window . requestAnimationFrame ||
window . webkitRequestAnimationFrame ||
window . mozRequestAnimationFrame ||
window . oRequestAnimationFrame ||
window . msRequestAnimationFrame ||
function ( callback ) {
return window . setTimeout ( callback , 1000 / 60 ) ;
} ;
} ) ( ) ;
helpers . cancelAnimFrame = ( function ( ) {
return window . cancelAnimationFrame ||
window . webkitCancelAnimationFrame ||
window . mozCancelAnimationFrame ||
window . oCancelAnimationFrame ||
window . msCancelAnimationFrame ||
function ( callback ) {
return window . clearTimeout ( callback , 1000 / 60 ) ;
} ;
} ) ( ) ;
//-- DOM methods
helpers . getRelativePosition = function ( evt , chart ) {
var mouseX , mouseY ;
var e = evt . originalEvent || evt ,
canvas = evt . currentTarget || evt . srcElement ,
boundingRect = canvas . getBoundingClientRect ( ) ;
if ( e . touches && e . touches . length > 0 ) {
mouseX = e . touches [ 0 ] . clientX ;
mouseY = e . touches [ 0 ] . clientY ;
} else {
mouseX = e . clientX ;
mouseY = e . clientY ;
}
// Scale mouse coordinates into canvas coordinates
// by following the pattern laid out by 'jerryj' in the comments of
// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
var paddingLeft = parseFloat ( helpers . getStyle ( canvas , 'padding-left' ) ) ;
var paddingTop = parseFloat ( helpers . getStyle ( canvas , 'padding-top' ) ) ;
var paddingRight = parseFloat ( helpers . getStyle ( canvas , 'padding-right' ) ) ;
var paddingBottom = parseFloat ( helpers . getStyle ( canvas , 'padding-bottom' ) ) ;
var width = boundingRect . right - boundingRect . left - paddingLeft - paddingRight ;
var height = boundingRect . bottom - boundingRect . top - paddingTop - paddingBottom ;
// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
mouseX = Math . round ( ( mouseX - boundingRect . left - paddingLeft ) / ( width ) * canvas . width / chart . currentDevicePixelRatio ) ;
mouseY = Math . round ( ( mouseY - boundingRect . top - paddingTop ) / ( height ) * canvas . height / chart . currentDevicePixelRatio ) ;
return {
x : mouseX ,
y : mouseY
} ;
} ;
helpers . addEvent = function ( node , eventType , method ) {
if ( node . addEventListener ) {
node . addEventListener ( eventType , method ) ;
} else if ( node . attachEvent ) {
node . attachEvent ( "on" + eventType , method ) ;
} else {
node [ "on" + eventType ] = method ;
}
} ;
helpers . removeEvent = function ( node , eventType , handler ) {
if ( node . removeEventListener ) {
node . removeEventListener ( eventType , handler , false ) ;
} else if ( node . detachEvent ) {
node . detachEvent ( "on" + eventType , handler ) ;
} else {
node [ "on" + eventType ] = helpers . noop ;
}
} ;
helpers . bindEvents = function ( chartInstance , arrayOfEvents , handler ) {
// Create the events object if it's not already present
if ( ! chartInstance . events )
chartInstance . events = { } ;
helpers . each ( arrayOfEvents , function ( eventName ) {
chartInstance . events [ eventName ] = function ( ) {
handler . apply ( chartInstance , arguments ) ;
} ;
helpers . addEvent ( chartInstance . chart . canvas , eventName , chartInstance . events [ eventName ] ) ;
} ) ;
} ;
helpers . unbindEvents = function ( chartInstance , arrayOfEvents ) {
helpers . each ( arrayOfEvents , function ( handler , eventName ) {
helpers . removeEvent ( chartInstance . chart . canvas , eventName , handler ) ;
} ) ;
} ;
// Private helper function to convert max-width/max-height values that may be percentages into a number
function parseMaxStyle ( styleValue , node , parentProperty ) {
var valueInPixels ;
if ( typeof ( styleValue ) === 'string' ) {
valueInPixels = parseInt ( styleValue , 10 ) ;
if ( styleValue . indexOf ( '%' ) != - 1 ) {
// percentage * size in dimension
valueInPixels = valueInPixels / 100 * node . parentNode [ parentProperty ] ;
}
} else {
valueInPixels = styleValue ;
}
return valueInPixels ;
}
// Private helper to get a constraint dimension
// @param domNode : the node to check the constraint on
// @param maxStyle : the style that defines the maximum for the direction we are using (max-width / max-height)
// @param percentageProperty : property of parent to use when calculating width as a percentage
function getConstraintDimension ( domNode , maxStyle , percentageProperty ) {
var constrainedDimension ;
var constrainedNode = document . defaultView . getComputedStyle ( domNode ) [ maxStyle ] ;
var constrainedContainer = document . defaultView . getComputedStyle ( domNode . parentNode ) [ maxStyle ] ;
var hasCNode = constrainedNode !== null && constrainedNode !== "none" ;
var hasCContainer = constrainedContainer !== null && constrainedContainer !== "none" ;
if ( hasCNode || hasCContainer ) {
constrainedDimension = Math . min ( ( hasCNode ? parseMaxStyle ( constrainedNode , domNode , percentageProperty ) : Number . POSITIVE _INFINITY ) , ( hasCContainer ? parseMaxStyle ( constrainedContainer , domNode . parentNode , percentageProperty ) : Number . POSITIVE _INFINITY ) ) ;
}
return constrainedDimension ;
}
// returns Number or undefined if no constraint
helpers . getConstraintWidth = function ( domNode ) {
return getConstraintDimension ( domNode , 'max-width' , 'clientWidth' ) ;
} ;
// returns Number or undefined if no constraint
helpers . getConstraintHeight = function ( domNode ) {
return getConstraintDimension ( domNode , 'max-height' , 'clientHeight' ) ;
} ;
helpers . getMaximumWidth = function ( domNode ) {
var container = domNode . parentNode ;
var padding = parseInt ( helpers . getStyle ( container , 'padding-left' ) ) + parseInt ( helpers . getStyle ( container , 'padding-right' ) ) ;
var w = container . clientWidth - padding ;
var cw = helpers . getConstraintWidth ( domNode ) ;
if ( cw !== undefined ) {
w = Math . min ( w , cw ) ;
}
return w ;
} ;
helpers . getMaximumHeight = function ( domNode ) {
var container = domNode . parentNode ;
var padding = parseInt ( helpers . getStyle ( container , 'padding-top' ) ) + parseInt ( helpers . getStyle ( container , 'padding-bottom' ) ) ;
var h = container . clientHeight - padding ;
var ch = helpers . getConstraintHeight ( domNode ) ;
if ( ch !== undefined ) {
h = Math . min ( h , ch ) ;
}
return h ;
} ;
helpers . getStyle = function ( el , property ) {
return el . currentStyle ?
el . currentStyle [ property ] :
document . defaultView . getComputedStyle ( el , null ) . getPropertyValue ( property ) ;
} ;
helpers . retinaScale = function ( chart ) {
var ctx = chart . ctx ;
var width = chart . canvas . width ;
var height = chart . canvas . height ;
var pixelRatio = chart . currentDevicePixelRatio = window . devicePixelRatio || 1 ;
if ( pixelRatio !== 1 ) {
ctx . canvas . height = height * pixelRatio ;
ctx . canvas . width = width * pixelRatio ;
ctx . scale ( pixelRatio , pixelRatio ) ;
// Store the device pixel ratio so that we can go backwards in `destroy`.
// The devicePixelRatio changes with zoom, so there are no guarantees that it is the same
// when destroy is called
chart . originalDevicePixelRatio = chart . originalDevicePixelRatio || pixelRatio ;
}
ctx . canvas . style . width = width + 'px' ;
ctx . canvas . style . height = height + 'px' ;
} ;
//-- Canvas methods
helpers . clear = function ( chart ) {
chart . ctx . clearRect ( 0 , 0 , chart . width , chart . height ) ;
} ;
helpers . fontString = function ( pixelSize , fontStyle , fontFamily ) {
return fontStyle + " " + pixelSize + "px " + fontFamily ;
} ;
helpers . longestText = function ( ctx , font , arrayOfStrings , cache ) {
cache = cache || { } ;
cache . data = cache . data || { } ;
cache . garbageCollect = cache . garbageCollect || [ ] ;
if ( cache . font !== font ) {
cache . data = { } ;
cache . garbageCollect = [ ] ;
cache . font = font ;
}
ctx . font = font ;
var longest = 0 ;
helpers . each ( arrayOfStrings , function ( string ) {
// Undefined strings should not be measured
if ( string !== undefined && string !== null ) {
var textWidth = cache . data [ string ] ;
if ( ! textWidth ) {
textWidth = cache . data [ string ] = ctx . measureText ( string ) . width ;
cache . garbageCollect . push ( string ) ;
}
if ( textWidth > longest ) {
longest = textWidth ;
}
}
} ) ;
var gcLen = cache . garbageCollect . length / 2 ;
if ( gcLen > arrayOfStrings . length ) {
for ( var i = 0 ; i < gcLen ; i ++ ) {
delete cache . data [ cache . garbageCollect [ i ] ] ;
}
cache . garbageCollect . splice ( 0 , gcLen ) ;
}
return longest ;
} ;
helpers . drawRoundedRectangle = function ( ctx , x , y , width , height , radius ) {
ctx . beginPath ( ) ;
ctx . moveTo ( x + radius , y ) ;
ctx . lineTo ( x + width - radius , y ) ;
ctx . quadraticCurveTo ( x + width , y , x + width , y + radius ) ;
ctx . lineTo ( x + width , y + height - radius ) ;
ctx . quadraticCurveTo ( x + width , y + height , x + width - radius , y + height ) ;
ctx . lineTo ( x + radius , y + height ) ;
ctx . quadraticCurveTo ( x , y + height , x , y + height - radius ) ;
ctx . lineTo ( x , y + radius ) ;
ctx . quadraticCurveTo ( x , y , x + radius , y ) ;
ctx . closePath ( ) ;
} ;
helpers . color = function ( c ) {
if ( ! color ) {
console . log ( 'Color.js not found!' ) ;
return c ;
}
/* global CanvasGradient */
if ( c instanceof CanvasGradient ) {
return color ( Chart . defaults . global . defaultColor ) ;
}
return color ( c ) ;
} ;
helpers . addResizeListener = function ( node , callback ) {
// Hide an iframe before the node
var hiddenIframe = document . createElement ( 'iframe' ) ;
var hiddenIframeClass = 'chartjs-hidden-iframe' ;
if ( hiddenIframe . classlist ) {
// can use classlist
hiddenIframe . classlist . add ( hiddenIframeClass ) ;
} else {
hiddenIframe . setAttribute ( 'class' , hiddenIframeClass ) ;
}
// Set the style
hiddenIframe . style . width = '100%' ;
hiddenIframe . style . display = 'block' ;
hiddenIframe . style . border = 0 ;
hiddenIframe . style . height = 0 ;
hiddenIframe . style . margin = 0 ;
hiddenIframe . style . position = 'absolute' ;
hiddenIframe . style . left = 0 ;
hiddenIframe . style . right = 0 ;
hiddenIframe . style . top = 0 ;
hiddenIframe . style . bottom = 0 ;
// Insert the iframe so that contentWindow is available
node . insertBefore ( hiddenIframe , node . firstChild ) ;
( hiddenIframe . contentWindow || hiddenIframe ) . onresize = function ( ) {
if ( callback ) {
callback ( ) ;
}
} ;
} ;
helpers . removeResizeListener = function ( node ) {
var hiddenIframe = node . querySelector ( '.chartjs-hidden-iframe' ) ;
// Remove the resize detect iframe
if ( hiddenIframe ) {
hiddenIframe . parentNode . removeChild ( hiddenIframe ) ;
}
} ;
helpers . isArray = function ( obj ) {
if ( ! Array . isArray ) {
return Object . prototype . toString . call ( obj ) === '[object Array]' ;
}
return Array . isArray ( obj ) ;
} ;
helpers . pushAllIfDefined = function ( element , array ) {
if ( typeof element === "undefined" ) {
return ;
}
if ( helpers . isArray ( element ) ) {
array . push . apply ( array , element ) ;
} else {
array . push ( element ) ;
}
} ;
helpers . callCallback = function ( fn , args , _tArg ) {
if ( fn && typeof fn . call === 'function' ) {
fn . apply ( _tArg , args ) ;
}
} ;
helpers . getHoverColor = function ( color ) {
/* global CanvasPattern */
return ( color instanceof CanvasPattern ) ?
color :
helpers . color ( color ) . saturate ( 0.5 ) . darken ( 0.1 ) . rgbString ( ) ;
} ;
} ;
} , { "chartjs-color" : 2 } ] , 26 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( ) {
//Occupy the global variable of Chart, and create a simple base class
var Chart = function ( context , config ) {
this . config = config ;
// Support a jQuery'd canvas element
if ( context . length && context [ 0 ] . getContext ) {
context = context [ 0 ] ;
}
// Support a canvas domnode
if ( context . getContext ) {
context = context . getContext ( "2d" ) ;
}
this . ctx = context ;
this . canvas = context . canvas ;
// Figure out what the size of the chart will be.
// If the canvas has a specified width and height, we use those else
// we look to see if the canvas node has a CSS width and height.
// If there is still no height, fill the parent container
this . width = context . canvas . width || parseInt ( Chart . helpers . getStyle ( context . canvas , 'width' ) ) || Chart . helpers . getMaximumWidth ( context . canvas ) ;
this . height = context . canvas . height || parseInt ( Chart . helpers . getStyle ( context . canvas , 'height' ) ) || Chart . helpers . getMaximumHeight ( context . canvas ) ;
this . aspectRatio = this . width / this . height ;
if ( isNaN ( this . aspectRatio ) || isFinite ( this . aspectRatio ) === false ) {
// If the canvas has no size, try and figure out what the aspect ratio will be.
// Some charts prefer square canvases (pie, radar, etc). If that is specified, use that
// else use the canvas default ratio of 2
this . aspectRatio = config . aspectRatio !== undefined ? config . aspectRatio : 2 ;
}
// Store the original style of the element so we can set it back
this . originalCanvasStyleWidth = context . canvas . style . width ;
this . originalCanvasStyleHeight = context . canvas . style . height ;
// High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
Chart . helpers . retinaScale ( this ) ;
if ( config ) {
this . controller = new Chart . Controller ( this ) ;
}
// Always bind this so that if the responsive state changes we still work
var _this = this ;
Chart . helpers . addResizeListener ( context . canvas . parentNode , function ( ) {
if ( _this . controller && _this . controller . config . options . responsive ) {
_this . controller . resize ( ) ;
}
} ) ;
return this . controller ? this . controller : this ;
} ;
//Globally expose the defaults to allow for user updating/changing
Chart . defaults = {
global : {
responsive : true ,
responsiveAnimationDuration : 0 ,
maintainAspectRatio : true ,
events : [ "mousemove" , "mouseout" , "click" , "touchstart" , "touchmove" ] ,
hover : {
onHover : null ,
mode : 'single' ,
animationDuration : 400
} ,
onClick : null ,
defaultColor : 'rgba(0,0,0,0.1)' ,
defaultFontColor : '#666' ,
defaultFontFamily : "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" ,
defaultFontSize : 12 ,
defaultFontStyle : 'normal' ,
showLines : true ,
// Element defaults defined in element extensions
elements : { } ,
// Legend callback string
legendCallback : function ( chart ) {
var text = [ ] ;
text . push ( '<ul class="' + chart . id + '-legend">' ) ;
for ( var i = 0 ; i < chart . data . datasets . length ; i ++ ) {
text . push ( '<li><span style="background-color:' + chart . data . datasets [ i ] . backgroundColor + '"></span>' ) ;
if ( chart . data . datasets [ i ] . label ) {
text . push ( chart . data . datasets [ i ] . label ) ;
}
text . push ( '</li>' ) ;
}
text . push ( '</ul>' ) ;
return text . join ( "" ) ;
}
}
} ;
return Chart ;
} ;
} , { } ] , 27 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
// The layout service is very self explanatory. It's responsible for the layout within a chart.
// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
// It is this service's responsibility of carrying out that layout.
Chart . layoutService = {
defaults : { } ,
// Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.
addBox : function ( chartInstance , box ) {
if ( ! chartInstance . boxes ) {
chartInstance . boxes = [ ] ;
}
chartInstance . boxes . push ( box ) ;
} ,
removeBox : function ( chartInstance , box ) {
if ( ! chartInstance . boxes ) {
return ;
}
chartInstance . boxes . splice ( chartInstance . boxes . indexOf ( box ) , 1 ) ;
} ,
// The most important function
update : function ( chartInstance , width , height ) {
if ( ! chartInstance ) {
return ;
}
var xPadding = 0 ;
var yPadding = 0 ;
var leftBoxes = helpers . where ( chartInstance . boxes , function ( box ) {
return box . options . position === "left" ;
} ) ;
var rightBoxes = helpers . where ( chartInstance . boxes , function ( box ) {
return box . options . position === "right" ;
} ) ;
var topBoxes = helpers . where ( chartInstance . boxes , function ( box ) {
return box . options . position === "top" ;
} ) ;
var bottomBoxes = helpers . where ( chartInstance . boxes , function ( box ) {
return box . options . position === "bottom" ;
} ) ;
// Boxes that overlay the chartarea such as the radialLinear scale
var chartAreaBoxes = helpers . where ( chartInstance . boxes , function ( box ) {
return box . options . position === "chartArea" ;
} ) ;
// Ensure that full width boxes are at the very top / bottom
topBoxes . sort ( function ( a , b ) {
return ( b . options . fullWidth ? 1 : 0 ) - ( a . options . fullWidth ? 1 : 0 ) ;
} ) ;
bottomBoxes . sort ( function ( a , b ) {
return ( a . options . fullWidth ? 1 : 0 ) - ( b . options . fullWidth ? 1 : 0 ) ;
} ) ;
// Essentially we now have any number of boxes on each of the 4 sides.
// Our canvas looks like the following.
// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
// B1 is the bottom axis
// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
// an error will be thrown.
//
// |----------------------------------------------------|
// | T1 (Full Width) |
// |----------------------------------------------------|
// | | | T2 | |
// | |----|-------------------------------------|----|
// | | | C1 | | C2 | |
// | | |----| |----| |
// | | | | |
// | L1 | L2 | ChartArea (C0) | R1 |
// | | | | |
// | | |----| |----| |
// | | | C3 | | C4 | |
// | |----|-------------------------------------|----|
// | | | B1 | |
// |----------------------------------------------------|
// | B2 (Full Width) |
// |----------------------------------------------------|
//
// What we do to find the best sizing, we do the following
// 1. Determine the minimum size of the chart area.
// 2. Split the remaining width equally between each vertical axis
// 3. Split the remaining height equally between each horizontal axis
// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
// 5. Adjust the sizes of each axis based on it's minimum reported size.
// 6. Refit each axis
// 7. Position each axis in the final location
// 8. Tell the chart the final location of the chart area
// 9. Tell any axes that overlay the chart area the positions of the chart area
// Step 1
var chartWidth = width - ( 2 * xPadding ) ;
var chartHeight = height - ( 2 * yPadding ) ;
var chartAreaWidth = chartWidth / 2 ; // min 50%
var chartAreaHeight = chartHeight / 2 ; // min 50%
// Step 2
var verticalBoxWidth = ( width - chartAreaWidth ) / ( leftBoxes . length + rightBoxes . length ) ;
// Step 3
var horizontalBoxHeight = ( height - chartAreaHeight ) / ( topBoxes . length + bottomBoxes . length ) ;
// Step 4
var maxChartAreaWidth = chartWidth ;
var maxChartAreaHeight = chartHeight ;
var minBoxSizes = [ ] ;
helpers . each ( leftBoxes . concat ( rightBoxes , topBoxes , bottomBoxes ) , getMinimumBoxSize ) ;
function getMinimumBoxSize ( box ) {
var minSize ;
var isHorizontal = box . isHorizontal ( ) ;
if ( isHorizontal ) {
minSize = box . update ( box . options . fullWidth ? chartWidth : maxChartAreaWidth , horizontalBoxHeight ) ;
maxChartAreaHeight -= minSize . height ;
} else {
minSize = box . update ( verticalBoxWidth , chartAreaHeight ) ;
maxChartAreaWidth -= minSize . width ;
}
minBoxSizes . push ( {
horizontal : isHorizontal ,
minSize : minSize ,
box : box
} ) ;
}
// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
// be if the axes are drawn at their minimum sizes.
// Steps 5 & 6
var totalLeftBoxesWidth = xPadding ;
var totalRightBoxesWidth = xPadding ;
var totalTopBoxesHeight = yPadding ;
var totalBottomBoxesHeight = yPadding ;
// Update, and calculate the left and right margins for the horizontal boxes
helpers . each ( leftBoxes . concat ( rightBoxes ) , fitBox ) ;
helpers . each ( leftBoxes , function ( box ) {
totalLeftBoxesWidth += box . width ;
} ) ;
helpers . each ( rightBoxes , function ( box ) {
totalRightBoxesWidth += box . width ;
} ) ;
// Set the Left and Right margins for the horizontal boxes
helpers . each ( topBoxes . concat ( bottomBoxes ) , fitBox ) ;
// Function to fit a box
function fitBox ( box ) {
var minBoxSize = helpers . findNextWhere ( minBoxSizes , function ( minBoxSize ) {
return minBoxSize . box === box ;
} ) ;
if ( minBoxSize ) {
if ( box . isHorizontal ( ) ) {
var scaleMargin = {
left : totalLeftBoxesWidth ,
right : totalRightBoxesWidth ,
top : 0 ,
bottom : 0
} ;
// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
// on the margin. Sometimes they need to increase in size slightly
box . update ( box . options . fullWidth ? chartWidth : maxChartAreaWidth , chartHeight / 2 , scaleMargin ) ;
} else {
box . update ( minBoxSize . minSize . width , maxChartAreaHeight ) ;
}
}
}
// Figure out how much margin is on the top and bottom of the vertical boxes
helpers . each ( topBoxes , function ( box ) {
totalTopBoxesHeight += box . height ;
} ) ;
helpers . each ( bottomBoxes , function ( box ) {
totalBottomBoxesHeight += box . height ;
} ) ;
// Let the left layout know the final margin
helpers . each ( leftBoxes . concat ( rightBoxes ) , finalFitVerticalBox ) ;
function finalFitVerticalBox ( box ) {
var minBoxSize = helpers . findNextWhere ( minBoxSizes , function ( minBoxSize ) {
return minBoxSize . box === box ;
} ) ;
var scaleMargin = {
left : 0 ,
right : 0 ,
top : totalTopBoxesHeight ,
bottom : totalBottomBoxesHeight
} ;
if ( minBoxSize ) {
box . update ( minBoxSize . minSize . width , maxChartAreaHeight , scaleMargin ) ;
}
}
// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
totalLeftBoxesWidth = xPadding ;
totalRightBoxesWidth = xPadding ;
totalTopBoxesHeight = yPadding ;
totalBottomBoxesHeight = yPadding ;
helpers . each ( leftBoxes , function ( box ) {
totalLeftBoxesWidth += box . width ;
} ) ;
helpers . each ( rightBoxes , function ( box ) {
totalRightBoxesWidth += box . width ;
} ) ;
helpers . each ( topBoxes , function ( box ) {
totalTopBoxesHeight += box . height ;
} ) ;
helpers . each ( bottomBoxes , function ( box ) {
totalBottomBoxesHeight += box . height ;
} ) ;
// Figure out if our chart area changed. This would occur if the dataset layout label rotation
// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
// without calling `fit` again
var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight ;
var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth ;
if ( newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight ) {
helpers . each ( leftBoxes , function ( box ) {
box . height = newMaxChartAreaHeight ;
} ) ;
helpers . each ( rightBoxes , function ( box ) {
box . height = newMaxChartAreaHeight ;
} ) ;
helpers . each ( topBoxes , function ( box ) {
if ( ! box . options . fullWidth ) {
box . width = newMaxChartAreaWidth ;
}
} ) ;
helpers . each ( bottomBoxes , function ( box ) {
if ( ! box . options . fullWidth ) {
box . width = newMaxChartAreaWidth ;
}
} ) ;
maxChartAreaHeight = newMaxChartAreaHeight ;
maxChartAreaWidth = newMaxChartAreaWidth ;
}
// Step 7 - Position the boxes
var left = xPadding ;
var top = yPadding ;
var right = 0 ;
var bottom = 0 ;
helpers . each ( leftBoxes . concat ( topBoxes ) , placeBox ) ;
// Account for chart width and height
left += maxChartAreaWidth ;
top += maxChartAreaHeight ;
helpers . each ( rightBoxes , placeBox ) ;
helpers . each ( bottomBoxes , placeBox ) ;
function placeBox ( box ) {
if ( box . isHorizontal ( ) ) {
box . left = box . options . fullWidth ? xPadding : totalLeftBoxesWidth ;
box . right = box . options . fullWidth ? width - xPadding : totalLeftBoxesWidth + maxChartAreaWidth ;
box . top = top ;
box . bottom = top + box . height ;
// Move to next point
top = box . bottom ;
} else {
box . left = left ;
box . right = left + box . width ;
box . top = totalTopBoxesHeight ;
box . bottom = totalTopBoxesHeight + maxChartAreaHeight ;
// Move to next point
left = box . right ;
}
}
// Step 8
chartInstance . chartArea = {
left : totalLeftBoxesWidth ,
top : totalTopBoxesHeight ,
right : totalLeftBoxesWidth + maxChartAreaWidth ,
bottom : totalTopBoxesHeight + maxChartAreaHeight
} ;
// Step 9
helpers . each ( chartAreaBoxes , function ( box ) {
box . left = chartInstance . chartArea . left ;
box . top = chartInstance . chartArea . top ;
box . right = chartInstance . chartArea . right ;
box . bottom = chartInstance . chartArea . bottom ;
box . update ( maxChartAreaWidth , maxChartAreaHeight ) ;
} ) ;
}
} ;
} ;
} , { } ] , 28 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var noop = helpers . noop ;
Chart . defaults . global . legend = {
display : true ,
position : 'top' ,
fullWidth : true , // marks that this box should take the full width of the canvas (pushing down other boxes)
reverse : false ,
// a callback that will handle
onClick : function ( e , legendItem ) {
var index = legendItem . datasetIndex ;
var ci = this . chart ;
var meta = ci . getDatasetMeta ( index ) ;
// See controller.isDatasetVisible comment
meta . hidden = meta . hidden === null ? ! ci . data . datasets [ index ] . hidden : null ;
// We hid a dataset ... rerender the chart
ci . update ( ) ;
} ,
labels : {
boxWidth : 40 ,
padding : 10 ,
// Generates labels shown in the legend
// Valid properties to return:
// text : text to display
// fillStyle : fill of coloured box
// strokeStyle: stroke of coloured box
// hidden : if this legend item refers to a hidden item
// lineCap : cap style for line
// lineDash
// lineDashOffset :
// lineJoin :
// lineWidth :
generateLabels : function ( chart ) {
var data = chart . data ;
return helpers . isArray ( data . datasets ) ? data . datasets . map ( function ( dataset , i ) {
return {
text : dataset . label ,
fillStyle : dataset . backgroundColor ,
hidden : ! chart . isDatasetVisible ( i ) ,
lineCap : dataset . borderCapStyle ,
lineDash : dataset . borderDash ,
lineDashOffset : dataset . borderDashOffset ,
lineJoin : dataset . borderJoinStyle ,
lineWidth : dataset . borderWidth ,
strokeStyle : dataset . borderColor ,
// Below is extra data used for toggling the datasets
datasetIndex : i
} ;
} , this ) : [ ] ;
}
}
} ;
Chart . Legend = Chart . Element . extend ( {
initialize : function ( config ) {
helpers . extend ( this , config ) ;
// Contains hit boxes for each dataset (in dataset order)
this . legendHitBoxes = [ ] ;
// Are we in doughnut mode which has a different data type
this . doughnutMode = false ;
} ,
// These methods are ordered by lifecyle. Utilities then follow.
// Any function defined here is inherited by all legend types.
// Any function can be extended by the legend type
beforeUpdate : noop ,
update : function ( maxWidth , maxHeight , margins ) {
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
this . beforeUpdate ( ) ;
// Absorb the master measurements
this . maxWidth = maxWidth ;
this . maxHeight = maxHeight ;
this . margins = margins ;
// Dimensions
this . beforeSetDimensions ( ) ;
this . setDimensions ( ) ;
this . afterSetDimensions ( ) ;
// Labels
this . beforeBuildLabels ( ) ;
this . buildLabels ( ) ;
this . afterBuildLabels ( ) ;
// Fit
this . beforeFit ( ) ;
this . fit ( ) ;
this . afterFit ( ) ;
//
this . afterUpdate ( ) ;
return this . minSize ;
} ,
afterUpdate : noop ,
//
beforeSetDimensions : noop ,
setDimensions : function ( ) {
// Set the unconstrained dimension before label rotation
if ( this . isHorizontal ( ) ) {
// Reset position before calculating rotation
this . width = this . maxWidth ;
this . left = 0 ;
this . right = this . width ;
} else {
this . height = this . maxHeight ;
// Reset position before calculating rotation
this . top = 0 ;
this . bottom = this . height ;
}
// Reset padding
this . paddingLeft = 0 ;
this . paddingTop = 0 ;
this . paddingRight = 0 ;
this . paddingBottom = 0 ;
// Reset minSize
this . minSize = {
width : 0 ,
height : 0
} ;
} ,
afterSetDimensions : noop ,
//
beforeBuildLabels : noop ,
buildLabels : function ( ) {
this . legendItems = this . options . labels . generateLabels . call ( this , this . chart ) ;
if ( this . options . reverse ) {
this . legendItems . reverse ( ) ;
}
} ,
afterBuildLabels : noop ,
//
beforeFit : noop ,
fit : function ( ) {
var opts = this . options ;
var labelOpts = opts . labels ;
var display = opts . display ;
var ctx = this . ctx ;
var globalDefault = Chart . defaults . global ,
itemOrDefault = helpers . getValueOrDefault ,
fontSize = itemOrDefault ( labelOpts . fontSize , globalDefault . defaultFontSize ) ,
fontStyle = itemOrDefault ( labelOpts . fontStyle , globalDefault . defaultFontStyle ) ,
fontFamily = itemOrDefault ( labelOpts . fontFamily , globalDefault . defaultFontFamily ) ,
labelFont = helpers . fontString ( fontSize , fontStyle , fontFamily ) ;
// Reset hit boxes
var hitboxes = this . legendHitBoxes = [ ] ;
var minSize = this . minSize ;
var isHorizontal = this . isHorizontal ( ) ;
if ( isHorizontal ) {
minSize . width = this . maxWidth ; // fill all the width
minSize . height = display ? 10 : 0 ;
} else {
minSize . width = display ? 10 : 0 ;
minSize . height = this . maxHeight ; // fill all the height
}
// Increase sizes here
if ( display ) {
if ( isHorizontal ) {
// Labels
// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
var lineWidths = this . lineWidths = [ 0 ] ;
var totalHeight = this . legendItems . length ? fontSize + ( labelOpts . padding ) : 0 ;
ctx . textAlign = "left" ;
ctx . textBaseline = 'top' ;
ctx . font = labelFont ;
helpers . each ( this . legendItems , function ( legendItem , i ) {
var width = labelOpts . boxWidth + ( fontSize / 2 ) + ctx . measureText ( legendItem . text ) . width ;
if ( lineWidths [ lineWidths . length - 1 ] + width + labelOpts . padding >= this . width ) {
totalHeight += fontSize + ( labelOpts . padding ) ;
lineWidths [ lineWidths . length ] = this . left ;
}
// Store the hitbox width and height here. Final position will be updated in `draw`
hitboxes [ i ] = {
left : 0 ,
top : 0 ,
width : width ,
height : fontSize
} ;
lineWidths [ lineWidths . length - 1 ] += width + labelOpts . padding ;
} , this ) ;
minSize . height += totalHeight ;
} else {
// TODO vertical
}
}
this . width = minSize . width ;
this . height = minSize . height ;
} ,
afterFit : noop ,
// Shared Methods
isHorizontal : function ( ) {
return this . options . position === "top" || this . options . position === "bottom" ;
} ,
// Actualy draw the legend on the canvas
draw : function ( ) {
var opts = this . options ;
var labelOpts = opts . labels ;
var globalDefault = Chart . defaults . global ,
lineDefault = globalDefault . elements . line ,
legendWidth = this . width ,
lineWidths = this . lineWidths ;
if ( opts . display ) {
var ctx = this . ctx ,
cursor = {
x : this . left + ( ( legendWidth - lineWidths [ 0 ] ) / 2 ) ,
y : this . top + labelOpts . padding ,
line : 0
} ,
itemOrDefault = helpers . getValueOrDefault ,
fontColor = itemOrDefault ( labelOpts . fontColor , globalDefault . defaultFontColor ) ,
fontSize = itemOrDefault ( labelOpts . fontSize , globalDefault . defaultFontSize ) ,
fontStyle = itemOrDefault ( labelOpts . fontStyle , globalDefault . defaultFontStyle ) ,
fontFamily = itemOrDefault ( labelOpts . fontFamily , globalDefault . defaultFontFamily ) ,
labelFont = helpers . fontString ( fontSize , fontStyle , fontFamily ) ;
// Horizontal
if ( this . isHorizontal ( ) ) {
// Labels
ctx . textAlign = "left" ;
ctx . textBaseline = 'top' ;
ctx . lineWidth = 0.5 ;
ctx . strokeStyle = fontColor ; // for strikethrough effect
ctx . fillStyle = fontColor ; // render in correct colour
ctx . font = labelFont ;
var boxWidth = labelOpts . boxWidth ,
hitboxes = this . legendHitBoxes ;
helpers . each ( this . legendItems , function ( legendItem , i ) {
var textWidth = ctx . measureText ( legendItem . text ) . width ,
width = boxWidth + ( fontSize / 2 ) + textWidth ,
x = cursor . x ,
y = cursor . y ;
if ( x + width >= legendWidth ) {
y = cursor . y += fontSize + ( labelOpts . padding ) ;
cursor . line ++ ;
x = cursor . x = this . left + ( ( legendWidth - lineWidths [ cursor . line ] ) / 2 ) ;
}
// Set the ctx for the box
ctx . save ( ) ;
ctx . fillStyle = itemOrDefault ( legendItem . fillStyle , globalDefault . defaultColor ) ;
ctx . lineCap = itemOrDefault ( legendItem . lineCap , lineDefault . borderCapStyle ) ;
ctx . lineDashOffset = itemOrDefault ( legendItem . lineDashOffset , lineDefault . borderDashOffset ) ;
ctx . lineJoin = itemOrDefault ( legendItem . lineJoin , lineDefault . borderJoinStyle ) ;
ctx . lineWidth = itemOrDefault ( legendItem . lineWidth , lineDefault . borderWidth ) ;
ctx . strokeStyle = itemOrDefault ( legendItem . strokeStyle , globalDefault . defaultColor ) ;
if ( ctx . setLineDash ) {
// IE 9 and 10 do not support line dash
ctx . setLineDash ( itemOrDefault ( legendItem . lineDash , lineDefault . borderDash ) ) ;
}
// Draw the box
ctx . strokeRect ( x , y , boxWidth , fontSize ) ;
ctx . fillRect ( x , y , boxWidth , fontSize ) ;
ctx . restore ( ) ;
hitboxes [ i ] . left = x ;
hitboxes [ i ] . top = y ;
// Fill the actual label
ctx . fillText ( legendItem . text , boxWidth + ( fontSize / 2 ) + x , y ) ;
if ( legendItem . hidden ) {
// Strikethrough the text if hidden
ctx . beginPath ( ) ;
ctx . lineWidth = 2 ;
ctx . moveTo ( boxWidth + ( fontSize / 2 ) + x , y + ( fontSize / 2 ) ) ;
ctx . lineTo ( boxWidth + ( fontSize / 2 ) + x + textWidth , y + ( fontSize / 2 ) ) ;
ctx . stroke ( ) ;
}
cursor . x += width + ( labelOpts . padding ) ;
} , this ) ;
} else {
}
}
} ,
// Handle an event
handleEvent : function ( e ) {
var position = helpers . getRelativePosition ( e , this . chart . chart ) ,
x = position . x ,
y = position . y ,
opts = this . options ;
if ( x >= this . left && x <= this . right && y >= this . top && y <= this . bottom ) {
// See if we are touching one of the dataset boxes
var lh = this . legendHitBoxes ;
for ( var i = 0 ; i < lh . length ; ++ i ) {
var hitBox = lh [ i ] ;
if ( x >= hitBox . left && x <= hitBox . left + hitBox . width && y >= hitBox . top && y <= hitBox . top + hitBox . height ) {
// Touching an element
if ( opts . onClick ) {
opts . onClick . call ( this , e , this . legendItems [ i ] ) ;
}
break ;
}
}
}
}
} ) ;
} ;
} , { } ] , 29 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
// Plugins are stored here
Chart . plugins = [ ] ;
Chart . pluginService = {
// Register a new plugin
register : function ( plugin ) {
var p = Chart . plugins ;
if ( p . indexOf ( plugin ) === - 1 ) {
p . push ( plugin ) ;
}
} ,
// Remove a registered plugin
remove : function ( plugin ) {
var p = Chart . plugins ;
var idx = p . indexOf ( plugin ) ;
if ( idx !== - 1 ) {
p . splice ( idx , 1 ) ;
}
} ,
// Iterate over all plugins
notifyPlugins : function ( method , args , scope ) {
helpers . each ( Chart . plugins , function ( plugin ) {
if ( plugin [ method ] && typeof plugin [ method ] === 'function' ) {
plugin [ method ] . apply ( scope , args ) ;
}
} , scope ) ;
}
} ;
var noop = helpers . noop ;
Chart . PluginBase = Chart . Element . extend ( {
// Plugin methods. All functions are passed the chart instance
// Called at start of chart init
beforeInit : noop ,
// Called at end of chart init
afterInit : noop ,
// Called at start of update
beforeUpdate : noop ,
// Called at end of update
afterUpdate : noop ,
// Called at start of draw
beforeDraw : noop ,
// Called at end of draw
afterDraw : noop ,
// Called during destroy
destroy : noop ,
} ) ;
} ;
} , { } ] , 30 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . scale = {
display : true ,
position : "left" ,
// grid line settings
gridLines : {
display : true ,
color : "rgba(0, 0, 0, 0.1)" ,
lineWidth : 1 ,
drawOnChartArea : true ,
drawTicks : true ,
tickMarkLength : 10 ,
zeroLineWidth : 1 ,
zeroLineColor : "rgba(0,0,0,0.25)" ,
offsetGridLines : false
} ,
// scale label
scaleLabel : {
// actual label
labelString : '' ,
// display property
display : false
} ,
// label settings
ticks : {
beginAtZero : false ,
minRotation : 0 ,
maxRotation : 50 ,
mirror : false ,
padding : 10 ,
reverse : false ,
display : true ,
autoSkip : true ,
autoSkipPadding : 0 ,
labelOffset : 0 ,
callback : function ( value ) {
return '' + value ;
}
}
} ;
Chart . Scale = Chart . Element . extend ( {
// These methods are ordered by lifecyle. Utilities then follow.
// Any function defined here is inherited by all scale types.
// Any function can be extended by the scale type
beforeUpdate : function ( ) {
helpers . callCallback ( this . options . beforeUpdate , [ this ] ) ;
} ,
update : function ( maxWidth , maxHeight , margins ) {
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
this . beforeUpdate ( ) ;
// Absorb the master measurements
this . maxWidth = maxWidth ;
this . maxHeight = maxHeight ;
this . margins = helpers . extend ( {
left : 0 ,
right : 0 ,
top : 0 ,
bottom : 0
} , margins ) ;
// Dimensions
this . beforeSetDimensions ( ) ;
this . setDimensions ( ) ;
this . afterSetDimensions ( ) ;
// Data min/max
this . beforeDataLimits ( ) ;
this . determineDataLimits ( ) ;
this . afterDataLimits ( ) ;
// Ticks
this . beforeBuildTicks ( ) ;
this . buildTicks ( ) ;
this . afterBuildTicks ( ) ;
this . beforeTickToLabelConversion ( ) ;
this . convertTicksToLabels ( ) ;
this . afterTickToLabelConversion ( ) ;
// Tick Rotation
this . beforeCalculateTickRotation ( ) ;
this . calculateTickRotation ( ) ;
this . afterCalculateTickRotation ( ) ;
// Fit
this . beforeFit ( ) ;
this . fit ( ) ;
this . afterFit ( ) ;
//
this . afterUpdate ( ) ;
return this . minSize ;
} ,
afterUpdate : function ( ) {
helpers . callCallback ( this . options . afterUpdate , [ this ] ) ;
} ,
//
beforeSetDimensions : function ( ) {
helpers . callCallback ( this . options . beforeSetDimensions , [ this ] ) ;
} ,
setDimensions : function ( ) {
// Set the unconstrained dimension before label rotation
if ( this . isHorizontal ( ) ) {
// Reset position before calculating rotation
this . width = this . maxWidth ;
this . left = 0 ;
this . right = this . width ;
} else {
this . height = this . maxHeight ;
// Reset position before calculating rotation
this . top = 0 ;
this . bottom = this . height ;
}
// Reset padding
this . paddingLeft = 0 ;
this . paddingTop = 0 ;
this . paddingRight = 0 ;
this . paddingBottom = 0 ;
} ,
afterSetDimensions : function ( ) {
helpers . callCallback ( this . options . afterSetDimensions , [ this ] ) ;
} ,
// Data limits
beforeDataLimits : function ( ) {
helpers . callCallback ( this . options . beforeDataLimits , [ this ] ) ;
} ,
determineDataLimits : helpers . noop ,
afterDataLimits : function ( ) {
helpers . callCallback ( this . options . afterDataLimits , [ this ] ) ;
} ,
//
beforeBuildTicks : function ( ) {
helpers . callCallback ( this . options . beforeBuildTicks , [ this ] ) ;
} ,
buildTicks : helpers . noop ,
afterBuildTicks : function ( ) {
helpers . callCallback ( this . options . afterBuildTicks , [ this ] ) ;
} ,
beforeTickToLabelConversion : function ( ) {
helpers . callCallback ( this . options . beforeTickToLabelConversion , [ this ] ) ;
} ,
convertTicksToLabels : function ( ) {
// Convert ticks to strings
this . ticks = this . ticks . map ( function ( numericalTick , index , ticks ) {
if ( this . options . ticks . userCallback ) {
return this . options . ticks . userCallback ( numericalTick , index , ticks ) ;
}
return this . options . ticks . callback ( numericalTick , index , ticks ) ;
} ,
this ) ;
} ,
afterTickToLabelConversion : function ( ) {
helpers . callCallback ( this . options . afterTickToLabelConversion , [ this ] ) ;
} ,
//
beforeCalculateTickRotation : function ( ) {
helpers . callCallback ( this . options . beforeCalculateTickRotation , [ this ] ) ;
} ,
calculateTickRotation : function ( ) {
//Get the width of each grid by calculating the difference
//between x offsets between 0 and 1.
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
var tickFontStyle = helpers . getValueOrDefault ( this . options . ticks . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var tickFontFamily = helpers . getValueOrDefault ( this . options . ticks . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var tickLabelFont = helpers . fontString ( tickFontSize , tickFontStyle , tickFontFamily ) ;
this . ctx . font = tickLabelFont ;
var firstWidth = this . ctx . measureText ( this . ticks [ 0 ] ) . width ;
var lastWidth = this . ctx . measureText ( this . ticks [ this . ticks . length - 1 ] ) . width ;
var firstRotated ;
this . labelRotation = this . options . ticks . minRotation || 0 ;
this . paddingRight = 0 ;
this . paddingLeft = 0 ;
if ( this . options . display ) {
if ( this . isHorizontal ( ) ) {
this . paddingRight = lastWidth / 2 + 3 ;
this . paddingLeft = firstWidth / 2 + 3 ;
if ( ! this . longestTextCache ) {
this . longestTextCache = { } ;
}
var originalLabelWidth = helpers . longestText ( this . ctx , tickLabelFont , this . ticks , this . longestTextCache ) ;
var labelWidth = originalLabelWidth ;
var cosRotation ;
var sinRotation ;
// Allow 3 pixels x2 padding either side for label readability
// only the index matters for a dataset scale, but we want a consistent interface between scales
var tickWidth = this . getPixelForTick ( 1 ) - this . getPixelForTick ( 0 ) - 6 ;
//Max label rotation can be set or default to 90 - also act as a loop counter
while ( labelWidth > tickWidth && this . labelRotation < this . options . ticks . maxRotation ) {
cosRotation = Math . cos ( helpers . toRadians ( this . labelRotation ) ) ;
sinRotation = Math . sin ( helpers . toRadians ( this . labelRotation ) ) ;
firstRotated = cosRotation * firstWidth ;
// We're right aligning the text now.
if ( firstRotated + tickFontSize / 2 > this . yLabelWidth ) {
this . paddingLeft = firstRotated + tickFontSize / 2 ;
}
this . paddingRight = tickFontSize / 2 ;
if ( sinRotation * originalLabelWidth > this . maxHeight ) {
// go back one step
this . labelRotation -- ;
break ;
}
this . labelRotation ++ ;
labelWidth = cosRotation * originalLabelWidth ;
}
}
}
if ( this . margins ) {
this . paddingLeft = Math . max ( this . paddingLeft - this . margins . left , 0 ) ;
this . paddingRight = Math . max ( this . paddingRight - this . margins . right , 0 ) ;
}
} ,
afterCalculateTickRotation : function ( ) {
helpers . callCallback ( this . options . afterCalculateTickRotation , [ this ] ) ;
} ,
//
beforeFit : function ( ) {
helpers . callCallback ( this . options . beforeFit , [ this ] ) ;
} ,
fit : function ( ) {
// Reset
var minSize = this . minSize = {
width : 0 ,
height : 0
} ;
var opts = this . options ;
var tickOpts = opts . ticks ;
var scaleLabelOpts = opts . scaleLabel ;
var globalOpts = Chart . defaults . global ;
var display = opts . display ;
var isHorizontal = this . isHorizontal ( ) ;
var tickFontSize = helpers . getValueOrDefault ( tickOpts . fontSize , globalOpts . defaultFontSize ) ;
var tickFontStyle = helpers . getValueOrDefault ( tickOpts . fontStyle , globalOpts . defaultFontStyle ) ;
var tickFontFamily = helpers . getValueOrDefault ( tickOpts . fontFamily , globalOpts . defaultFontFamily ) ;
var tickLabelFont = helpers . fontString ( tickFontSize , tickFontStyle , tickFontFamily ) ;
var scaleLabelFontSize = helpers . getValueOrDefault ( scaleLabelOpts . fontSize , globalOpts . defaultFontSize ) ;
var scaleLabelFontStyle = helpers . getValueOrDefault ( scaleLabelOpts . fontStyle , globalOpts . defaultFontStyle ) ;
var scaleLabelFontFamily = helpers . getValueOrDefault ( scaleLabelOpts . fontFamily , globalOpts . defaultFontFamily ) ;
var scaleLabelFont = helpers . fontString ( scaleLabelFontSize , scaleLabelFontStyle , scaleLabelFontFamily ) ;
var tickMarkLength = opts . gridLines . tickMarkLength ;
// Width
if ( isHorizontal ) {
// subtract the margins to line up with the chartArea if we are a full width scale
minSize . width = this . isFullWidth ( ) ? this . maxWidth - this . margins . left - this . margins . right : this . maxWidth ;
} else {
minSize . width = display ? tickMarkLength : 0 ;
}
// height
if ( isHorizontal ) {
minSize . height = display ? tickMarkLength : 0 ;
} else {
minSize . height = this . maxHeight ; // fill all the height
}
// Are we showing a title for the scale?
if ( scaleLabelOpts . display && display ) {
if ( isHorizontal ) {
minSize . height += ( scaleLabelFontSize * 1.5 ) ;
} else {
minSize . width += ( scaleLabelFontSize * 1.5 ) ;
}
}
if ( tickOpts . display && display ) {
// Don't bother fitting the ticks if we are not showing them
if ( ! this . longestTextCache ) {
this . longestTextCache = { } ;
}
var largestTextWidth = helpers . longestText ( this . ctx , tickLabelFont , this . ticks , this . longestTextCache ) ;
if ( isHorizontal ) {
// A horizontal axis is more constrained by the height.
this . longestLabelWidth = largestTextWidth ;
// TODO - improve this calculation
var labelHeight = ( Math . sin ( helpers . toRadians ( this . labelRotation ) ) * this . longestLabelWidth ) + 1.5 * tickFontSize ;
minSize . height = Math . min ( this . maxHeight , minSize . height + labelHeight ) ;
this . ctx . font = tickLabelFont ;
var firstLabelWidth = this . ctx . measureText ( this . ticks [ 0 ] ) . width ;
var lastLabelWidth = this . ctx . measureText ( this . ticks [ this . ticks . length - 1 ] ) . width ;
// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
// by the font height
var cosRotation = Math . cos ( helpers . toRadians ( this . labelRotation ) ) ;
var sinRotation = Math . sin ( helpers . toRadians ( this . labelRotation ) ) ;
this . paddingLeft = this . labelRotation !== 0 ? ( cosRotation * firstLabelWidth ) + 3 : firstLabelWidth / 2 + 3 ; // add 3 px to move away from canvas edges
this . paddingRight = this . labelRotation !== 0 ? ( sinRotation * ( tickFontSize / 2 ) ) + 3 : lastLabelWidth / 2 + 3 ; // when rotated
} else {
// A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
var maxLabelWidth = this . maxWidth - minSize . width ;
// Account for padding
var mirror = tickOpts . mirror ;
if ( ! mirror ) {
largestTextWidth += this . options . ticks . padding ;
} else {
// If mirrored text is on the inside so don't expand
largestTextWidth = 0 ;
}
if ( largestTextWidth < maxLabelWidth ) {
// We don't need all the room
minSize . width += largestTextWidth ;
} else {
// Expand to max size
minSize . width = this . maxWidth ;
}
this . paddingTop = tickFontSize / 2 ;
this . paddingBottom = tickFontSize / 2 ;
}
}
if ( this . margins ) {
this . paddingLeft = Math . max ( this . paddingLeft - this . margins . left , 0 ) ;
this . paddingTop = Math . max ( this . paddingTop - this . margins . top , 0 ) ;
this . paddingRight = Math . max ( this . paddingRight - this . margins . right , 0 ) ;
this . paddingBottom = Math . max ( this . paddingBottom - this . margins . bottom , 0 ) ;
}
this . width = minSize . width ;
this . height = minSize . height ;
} ,
afterFit : function ( ) {
helpers . callCallback ( this . options . afterFit , [ this ] ) ;
} ,
// Shared Methods
isHorizontal : function ( ) {
return this . options . position === "top" || this . options . position === "bottom" ;
} ,
isFullWidth : function ( ) {
return ( this . options . fullWidth ) ;
} ,
// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
getRightValue : function getRightValue ( rawValue ) {
// Null and undefined values first
if ( rawValue === null || typeof ( rawValue ) === 'undefined' ) {
return NaN ;
}
// isNaN(object) returns true, so make sure NaN is checking for a number
if ( typeof ( rawValue ) === 'number' && isNaN ( rawValue ) ) {
return NaN ;
}
// If it is in fact an object, dive in one more level
if ( typeof ( rawValue ) === "object" ) {
if ( rawValue instanceof Date ) {
return rawValue ;
} else {
return getRightValue ( this . isHorizontal ( ) ? rawValue . x : rawValue . y ) ;
}
}
// Value is good, return it
return rawValue ;
} ,
// Used to get the value to display in the tooltip for the data at the given index
// function getLabelForIndex(index, datasetIndex)
getLabelForIndex : helpers . noop ,
// Used to get data value locations. Value can either be an index or a numerical value
getPixelForValue : helpers . noop ,
// Used to get the data value from a given pixel. This is the inverse of getPixelForValue
getValueForPixel : helpers . noop ,
// Used for tick location, should
getPixelForTick : function ( index , includeOffset ) {
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
var tickWidth = innerWidth / Math . max ( ( this . ticks . length - ( ( this . options . gridLines . offsetGridLines ) ? 0 : 1 ) ) , 1 ) ;
var pixel = ( tickWidth * index ) + this . paddingLeft ;
if ( includeOffset ) {
pixel += tickWidth / 2 ;
}
var finalVal = this . left + Math . round ( pixel ) ;
finalVal += this . isFullWidth ( ) ? this . margins . left : 0 ;
return finalVal ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
return this . top + ( index * ( innerHeight / ( this . ticks . length - 1 ) ) ) ;
}
} ,
// Utility for getting the pixel location of a percentage of scale
getPixelForDecimal : function ( decimal /*, includeOffset*/ ) {
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
var valueOffset = ( innerWidth * decimal ) + this . paddingLeft ;
var finalVal = this . left + Math . round ( valueOffset ) ;
finalVal += this . isFullWidth ( ) ? this . margins . left : 0 ;
return finalVal ;
} else {
return this . top + ( decimal * this . height ) ;
}
} ,
// Actualy draw the scale on the canvas
// @param {rectangle} chartArea : the area of the chart to draw full grid lines on
draw : function ( chartArea ) {
if ( this . options . display ) {
var setContextLineSettings ;
var isRotated = this . labelRotation !== 0 ;
var skipRatio ;
var scaleLabelX ;
var scaleLabelY ;
var useAutoskipper = this . options . ticks . autoSkip ;
// figure out the maximum number of gridlines to show
var maxTicks ;
if ( this . options . ticks . maxTicksLimit ) {
maxTicks = this . options . ticks . maxTicksLimit ;
}
var tickFontColor = helpers . getValueOrDefault ( this . options . ticks . fontColor , Chart . defaults . global . defaultFontColor ) ;
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
var tickFontStyle = helpers . getValueOrDefault ( this . options . ticks . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var tickFontFamily = helpers . getValueOrDefault ( this . options . ticks . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var tickLabelFont = helpers . fontString ( tickFontSize , tickFontStyle , tickFontFamily ) ;
var tl = this . options . gridLines . tickMarkLength ;
var scaleLabelFontColor = helpers . getValueOrDefault ( this . options . scaleLabel . fontColor , Chart . defaults . global . defaultFontColor ) ;
var scaleLabelFontSize = helpers . getValueOrDefault ( this . options . scaleLabel . fontSize , Chart . defaults . global . defaultFontSize ) ;
var scaleLabelFontStyle = helpers . getValueOrDefault ( this . options . scaleLabel . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var scaleLabelFontFamily = helpers . getValueOrDefault ( this . options . scaleLabel . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var scaleLabelFont = helpers . fontString ( scaleLabelFontSize , scaleLabelFontStyle , scaleLabelFontFamily ) ;
var cosRotation = Math . cos ( helpers . toRadians ( this . labelRotation ) ) ;
var sinRotation = Math . sin ( helpers . toRadians ( this . labelRotation ) ) ;
var longestRotatedLabel = this . longestLabelWidth * cosRotation ;
var rotatedLabelHeight = tickFontSize * sinRotation ;
// Make sure we draw text in the correct color and font
this . ctx . fillStyle = tickFontColor ;
if ( this . isHorizontal ( ) ) {
setContextLineSettings = true ;
var yTickStart = this . options . position === "bottom" ? this . top : this . bottom - tl ;
var yTickEnd = this . options . position === "bottom" ? this . top + tl : this . bottom ;
skipRatio = false ;
if ( ( ( longestRotatedLabel / 2 ) + this . options . ticks . autoSkipPadding ) * this . ticks . length > ( this . width - ( this . paddingLeft + this . paddingRight ) ) ) {
skipRatio = 1 + Math . floor ( ( ( ( longestRotatedLabel / 2 ) + this . options . ticks . autoSkipPadding ) * this . ticks . length ) / ( this . width - ( this . paddingLeft + this . paddingRight ) ) ) ;
}
// if they defined a max number of ticks,
// increase skipRatio until that number is met
if ( maxTicks && this . ticks . length > maxTicks ) {
while ( ! skipRatio || this . ticks . length / ( skipRatio || 1 ) > maxTicks ) {
if ( ! skipRatio ) {
skipRatio = 1 ;
}
skipRatio += 1 ;
}
}
if ( ! useAutoskipper ) {
skipRatio = false ;
}
helpers . each ( this . ticks , function ( label , index ) {
// Blank ticks
var isLastTick = this . ticks . length === index + 1 ;
// Since we always show the last tick,we need may need to hide the last shown one before
var shouldSkip = ( skipRatio > 1 && index % skipRatio > 0 ) || ( index % skipRatio === 0 && index + skipRatio > this . ticks . length ) ;
if ( shouldSkip && ! isLastTick || ( label === undefined || label === null ) ) {
return ;
}
var xLineValue = this . getPixelForTick ( index ) ; // xvalues for grid lines
var xLabelValue = this . getPixelForTick ( index , this . options . gridLines . offsetGridLines ) ; // x values for ticks (need to consider offsetLabel option)
if ( this . options . gridLines . display ) {
if ( index === ( typeof this . zeroLineIndex !== 'undefined' ? this . zeroLineIndex : 0 ) ) {
// Draw the first index specially
this . ctx . lineWidth = this . options . gridLines . zeroLineWidth ;
this . ctx . strokeStyle = this . options . gridLines . zeroLineColor ;
setContextLineSettings = true ; // reset next time
} else if ( setContextLineSettings ) {
this . ctx . lineWidth = this . options . gridLines . lineWidth ;
this . ctx . strokeStyle = this . options . gridLines . color ;
setContextLineSettings = false ;
}
xLineValue += helpers . aliasPixel ( this . ctx . lineWidth ) ;
// Draw the label area
this . ctx . beginPath ( ) ;
if ( this . options . gridLines . drawTicks ) {
this . ctx . moveTo ( xLineValue , yTickStart ) ;
this . ctx . lineTo ( xLineValue , yTickEnd ) ;
}
// Draw the chart area
if ( this . options . gridLines . drawOnChartArea ) {
this . ctx . moveTo ( xLineValue , chartArea . top ) ;
this . ctx . lineTo ( xLineValue , chartArea . bottom ) ;
}
// Need to stroke in the loop because we are potentially changing line widths & colours
this . ctx . stroke ( ) ;
}
if ( this . options . ticks . display ) {
this . ctx . save ( ) ;
this . ctx . translate ( xLabelValue + this . options . ticks . labelOffset , ( isRotated ) ? this . top + 12 : this . options . position === "top" ? this . bottom - tl : this . top + tl ) ;
this . ctx . rotate ( helpers . toRadians ( this . labelRotation ) * - 1 ) ;
this . ctx . font = tickLabelFont ;
this . ctx . textAlign = ( isRotated ) ? "right" : "center" ;
this . ctx . textBaseline = ( isRotated ) ? "middle" : this . options . position === "top" ? "bottom" : "top" ;
this . ctx . fillText ( label , 0 , 0 ) ;
this . ctx . restore ( ) ;
}
} , this ) ;
if ( this . options . scaleLabel . display ) {
// Draw the scale label
this . ctx . textAlign = "center" ;
this . ctx . textBaseline = 'middle' ;
this . ctx . fillStyle = scaleLabelFontColor ; // render in correct colour
this . ctx . font = scaleLabelFont ;
scaleLabelX = this . left + ( ( this . right - this . left ) / 2 ) ; // midpoint of the width
scaleLabelY = this . options . position === 'bottom' ? this . bottom - ( scaleLabelFontSize / 2 ) : this . top + ( scaleLabelFontSize / 2 ) ;
this . ctx . fillText ( this . options . scaleLabel . labelString , scaleLabelX , scaleLabelY ) ;
}
} else {
setContextLineSettings = true ;
var xTickStart = this . options . position === "right" ? this . left : this . right - 5 ;
var xTickEnd = this . options . position === "right" ? this . left + 5 : this . right ;
helpers . each ( this . ticks , function ( label , index ) {
// If the callback returned a null or undefined value, do not draw this line
if ( label === undefined || label === null ) {
return ;
}
var yLineValue = this . getPixelForTick ( index ) ; // xvalues for grid lines
if ( this . options . gridLines . display ) {
if ( index === ( typeof this . zeroLineIndex !== 'undefined' ? this . zeroLineIndex : 0 ) ) {
// Draw the first index specially
this . ctx . lineWidth = this . options . gridLines . zeroLineWidth ;
this . ctx . strokeStyle = this . options . gridLines . zeroLineColor ;
setContextLineSettings = true ; // reset next time
} else if ( setContextLineSettings ) {
this . ctx . lineWidth = this . options . gridLines . lineWidth ;
this . ctx . strokeStyle = this . options . gridLines . color ;
setContextLineSettings = false ;
}
yLineValue += helpers . aliasPixel ( this . ctx . lineWidth ) ;
// Draw the label area
this . ctx . beginPath ( ) ;
if ( this . options . gridLines . drawTicks ) {
this . ctx . moveTo ( xTickStart , yLineValue ) ;
this . ctx . lineTo ( xTickEnd , yLineValue ) ;
}
// Draw the chart area
if ( this . options . gridLines . drawOnChartArea ) {
this . ctx . moveTo ( chartArea . left , yLineValue ) ;
this . ctx . lineTo ( chartArea . right , yLineValue ) ;
}
// Need to stroke in the loop because we are potentially changing line widths & colours
this . ctx . stroke ( ) ;
}
if ( this . options . ticks . display ) {
var xLabelValue ;
var yLabelValue = this . getPixelForTick ( index , this . options . gridLines . offsetGridLines ) ; // x values for ticks (need to consider offsetLabel option)
this . ctx . save ( ) ;
if ( this . options . position === "left" ) {
if ( this . options . ticks . mirror ) {
xLabelValue = this . right + this . options . ticks . padding ;
this . ctx . textAlign = "left" ;
} else {
xLabelValue = this . right - this . options . ticks . padding ;
this . ctx . textAlign = "right" ;
}
} else {
// right side
if ( this . options . ticks . mirror ) {
xLabelValue = this . left - this . options . ticks . padding ;
this . ctx . textAlign = "right" ;
} else {
xLabelValue = this . left + this . options . ticks . padding ;
this . ctx . textAlign = "left" ;
}
}
this . ctx . translate ( xLabelValue , yLabelValue + this . options . ticks . labelOffset ) ;
this . ctx . rotate ( helpers . toRadians ( this . labelRotation ) * - 1 ) ;
this . ctx . font = tickLabelFont ;
this . ctx . textBaseline = "middle" ;
this . ctx . fillText ( label , 0 , 0 ) ;
this . ctx . restore ( ) ;
}
} , this ) ;
if ( this . options . scaleLabel . display ) {
// Draw the scale label
scaleLabelX = this . options . position === 'left' ? this . left + ( scaleLabelFontSize / 2 ) : this . right - ( scaleLabelFontSize / 2 ) ;
scaleLabelY = this . top + ( ( this . bottom - this . top ) / 2 ) ;
var rotation = this . options . position === 'left' ? - 0.5 * Math . PI : 0.5 * Math . PI ;
this . ctx . save ( ) ;
this . ctx . translate ( scaleLabelX , scaleLabelY ) ;
this . ctx . rotate ( rotation ) ;
this . ctx . textAlign = "center" ;
this . ctx . fillStyle = scaleLabelFontColor ; // render in correct colour
this . ctx . font = scaleLabelFont ;
this . ctx . textBaseline = 'middle' ;
this . ctx . fillText ( this . options . scaleLabel . labelString , 0 , 0 ) ;
this . ctx . restore ( ) ;
}
}
// Draw the line at the edge of the axis
this . ctx . lineWidth = this . options . gridLines . lineWidth ;
this . ctx . strokeStyle = this . options . gridLines . color ;
var x1 = this . left ,
x2 = this . right ,
y1 = this . top ,
y2 = this . bottom ;
if ( this . isHorizontal ( ) ) {
y1 = y2 = this . options . position === 'top' ? this . bottom : this . top ;
y1 += helpers . aliasPixel ( this . ctx . lineWidth ) ;
y2 += helpers . aliasPixel ( this . ctx . lineWidth ) ;
} else {
x1 = x2 = this . options . position === 'left' ? this . right : this . left ;
x1 += helpers . aliasPixel ( this . ctx . lineWidth ) ;
x2 += helpers . aliasPixel ( this . ctx . lineWidth ) ;
}
this . ctx . beginPath ( ) ;
this . ctx . moveTo ( x1 , y1 ) ;
this . ctx . lineTo ( x2 , y2 ) ;
this . ctx . stroke ( ) ;
}
}
} ) ;
} ;
} , { } ] , 31 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . scaleService = {
// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
// use the new chart options to grab the correct scale
constructors : { } ,
// Use a registration function so that we can move to an ES6 map when we no longer need to support
// old browsers
// Scale config defaults
defaults : { } ,
registerScaleType : function ( type , scaleConstructor , defaults ) {
this . constructors [ type ] = scaleConstructor ;
this . defaults [ type ] = helpers . clone ( defaults ) ;
} ,
getScaleConstructor : function ( type ) {
return this . constructors . hasOwnProperty ( type ) ? this . constructors [ type ] : undefined ;
} ,
getScaleDefaults : function ( type ) {
// Return the scale defaults merged with the global settings so that we always use the latest ones
return this . defaults . hasOwnProperty ( type ) ? helpers . scaleMerge ( Chart . defaults . scale , this . defaults [ type ] ) : { } ;
} ,
updateScaleDefaults : function ( type , additions ) {
var defaults = this . defaults ;
if ( defaults . hasOwnProperty ( type ) ) {
defaults [ type ] = helpers . extend ( defaults [ type ] , additions ) ;
}
} ,
addScalesToLayout : function ( chartInstance ) {
// Adds each scale to the chart.boxes array to be sized accordingly
helpers . each ( chartInstance . scales , function ( scale ) {
Chart . layoutService . addBox ( chartInstance , scale ) ;
} ) ;
}
} ;
} ;
} , { } ] , 32 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . global . title = {
display : false ,
position : 'top' ,
fullWidth : true , // marks that this box should take the full width of the canvas (pushing down other boxes)
fontStyle : 'bold' ,
padding : 10 ,
// actual title
text : ''
} ;
var noop = helpers . noop ;
Chart . Title = Chart . Element . extend ( {
initialize : function ( config ) {
helpers . extend ( this , config ) ;
this . options = helpers . configMerge ( Chart . defaults . global . title , config . options ) ;
// Contains hit boxes for each dataset (in dataset order)
this . legendHitBoxes = [ ] ;
} ,
// These methods are ordered by lifecyle. Utilities then follow.
beforeUpdate : noop ,
update : function ( maxWidth , maxHeight , margins ) {
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
this . beforeUpdate ( ) ;
// Absorb the master measurements
this . maxWidth = maxWidth ;
this . maxHeight = maxHeight ;
this . margins = margins ;
// Dimensions
this . beforeSetDimensions ( ) ;
this . setDimensions ( ) ;
this . afterSetDimensions ( ) ;
// Labels
this . beforeBuildLabels ( ) ;
this . buildLabels ( ) ;
this . afterBuildLabels ( ) ;
// Fit
this . beforeFit ( ) ;
this . fit ( ) ;
this . afterFit ( ) ;
//
this . afterUpdate ( ) ;
return this . minSize ;
} ,
afterUpdate : noop ,
//
beforeSetDimensions : noop ,
setDimensions : function ( ) {
// Set the unconstrained dimension before label rotation
if ( this . isHorizontal ( ) ) {
// Reset position before calculating rotation
this . width = this . maxWidth ;
this . left = 0 ;
this . right = this . width ;
} else {
this . height = this . maxHeight ;
// Reset position before calculating rotation
this . top = 0 ;
this . bottom = this . height ;
}
// Reset padding
this . paddingLeft = 0 ;
this . paddingTop = 0 ;
this . paddingRight = 0 ;
this . paddingBottom = 0 ;
// Reset minSize
this . minSize = {
width : 0 ,
height : 0
} ;
} ,
afterSetDimensions : noop ,
//
beforeBuildLabels : noop ,
buildLabels : noop ,
afterBuildLabels : noop ,
//
beforeFit : noop ,
fit : function ( ) {
var ctx = this . ctx ,
valueOrDefault = helpers . getValueOrDefault ,
opts = this . options ,
globalDefaults = Chart . defaults . global ,
display = opts . display ,
fontSize = valueOrDefault ( opts . fontSize , globalDefaults . defaultFontSize ) ,
minSize = this . minSize ;
if ( this . isHorizontal ( ) ) {
minSize . width = this . maxWidth ; // fill all the width
minSize . height = display ? fontSize + ( opts . padding * 2 ) : 0 ;
} else {
minSize . width = display ? fontSize + ( opts . padding * 2 ) : 0 ;
minSize . height = this . maxHeight ; // fill all the height
}
this . width = minSize . width ;
this . height = minSize . height ;
} ,
afterFit : noop ,
// Shared Methods
isHorizontal : function ( ) {
var pos = this . options . position ;
return pos === "top" || pos === "bottom" ;
} ,
// Actualy draw the title block on the canvas
draw : function ( ) {
var ctx = this . ctx ,
valueOrDefault = helpers . getValueOrDefault ,
opts = this . options ,
globalDefaults = Chart . defaults . global ;
if ( opts . display ) {
var fontSize = valueOrDefault ( opts . fontSize , globalDefaults . defaultFontSize ) ,
fontStyle = valueOrDefault ( opts . fontStyle , globalDefaults . defaultFontStyle ) ,
fontFamily = valueOrDefault ( opts . fontFamily , globalDefaults . defaultFontFamily ) ,
titleFont = helpers . fontString ( fontSize , fontStyle , fontFamily ) ,
rotation = 0 ,
titleX ,
titleY ;
ctx . fillStyle = valueOrDefault ( opts . fontColor , globalDefaults . defaultFontColor ) ; // render in correct colour
ctx . font = titleFont ;
// Horizontal
if ( this . isHorizontal ( ) ) {
titleX = this . left + ( ( this . right - this . left ) / 2 ) ; // midpoint of the width
titleY = this . top + ( ( this . bottom - this . top ) / 2 ) ; // midpoint of the height
} else {
titleX = opts . position === 'left' ? this . left + ( fontSize / 2 ) : this . right - ( fontSize / 2 ) ;
titleY = this . top + ( ( this . bottom - this . top ) / 2 ) ;
rotation = Math . PI * ( opts . position === 'left' ? - 0.5 : 0.5 ) ;
}
ctx . save ( ) ;
ctx . translate ( titleX , titleY ) ;
ctx . rotate ( rotation ) ;
ctx . textAlign = 'center' ;
ctx . textBaseline = 'middle' ;
ctx . fillText ( opts . text , 0 , 0 ) ;
ctx . restore ( ) ;
}
}
} ) ;
} ;
} , { } ] , 33 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . global . tooltips = {
enabled : true ,
custom : null ,
mode : 'single' ,
backgroundColor : "rgba(0,0,0,0.8)" ,
titleFontStyle : "bold" ,
titleSpacing : 2 ,
titleMarginBottom : 6 ,
titleColor : "#fff" ,
titleAlign : "left" ,
bodySpacing : 2 ,
bodyColor : "#fff" ,
bodyAlign : "left" ,
footerFontStyle : "bold" ,
footerSpacing : 2 ,
footerMarginTop : 6 ,
footerColor : "#fff" ,
footerAlign : "left" ,
yPadding : 6 ,
xPadding : 6 ,
yAlign : 'center' ,
xAlign : 'center' ,
caretSize : 5 ,
cornerRadius : 6 ,
multiKeyBackground : '#fff' ,
callbacks : {
// Args are: (tooltipItems, data)
beforeTitle : helpers . noop ,
title : function ( tooltipItems , data ) {
// Pick first xLabel for now
var title = '' ;
if ( tooltipItems . length > 0 ) {
if ( tooltipItems [ 0 ] . xLabel ) {
title = tooltipItems [ 0 ] . xLabel ;
} else if ( data . labels . length > 0 && tooltipItems [ 0 ] . index < data . labels . length ) {
title = data . labels [ tooltipItems [ 0 ] . index ] ;
}
}
return title ;
} ,
afterTitle : helpers . noop ,
// Args are: (tooltipItems, data)
beforeBody : helpers . noop ,
// Args are: (tooltipItem, data)
beforeLabel : helpers . noop ,
label : function ( tooltipItem , data ) {
var datasetLabel = data . datasets [ tooltipItem . datasetIndex ] . label || '' ;
return datasetLabel + ': ' + tooltipItem . yLabel ;
} ,
afterLabel : helpers . noop ,
// Args are: (tooltipItems, data)
afterBody : helpers . noop ,
// Args are: (tooltipItems, data)
beforeFooter : helpers . noop ,
footer : helpers . noop ,
afterFooter : helpers . noop
}
} ;
// Helper to push or concat based on if the 2nd parameter is an array or not
function pushOrConcat ( base , toPush ) {
if ( toPush ) {
if ( helpers . isArray ( toPush ) ) {
base = base . concat ( toPush ) ;
} else {
base . push ( toPush ) ;
}
}
return base ;
}
Chart . Tooltip = Chart . Element . extend ( {
initialize : function ( ) {
var options = this . _options ;
helpers . extend ( this , {
_model : {
// Positioning
xPadding : options . tooltips . xPadding ,
yPadding : options . tooltips . yPadding ,
xAlign : options . tooltips . yAlign ,
yAlign : options . tooltips . xAlign ,
// Body
bodyColor : options . tooltips . bodyColor ,
_bodyFontFamily : helpers . getValueOrDefault ( options . tooltips . bodyFontFamily , Chart . defaults . global . defaultFontFamily ) ,
_bodyFontStyle : helpers . getValueOrDefault ( options . tooltips . bodyFontStyle , Chart . defaults . global . defaultFontStyle ) ,
_bodyAlign : options . tooltips . bodyAlign ,
bodyFontSize : helpers . getValueOrDefault ( options . tooltips . bodyFontSize , Chart . defaults . global . defaultFontSize ) ,
bodySpacing : options . tooltips . bodySpacing ,
// Title
titleColor : options . tooltips . titleColor ,
_titleFontFamily : helpers . getValueOrDefault ( options . tooltips . titleFontFamily , Chart . defaults . global . defaultFontFamily ) ,
_titleFontStyle : helpers . getValueOrDefault ( options . tooltips . titleFontStyle , Chart . defaults . global . defaultFontStyle ) ,
titleFontSize : helpers . getValueOrDefault ( options . tooltips . titleFontSize , Chart . defaults . global . defaultFontSize ) ,
_titleAlign : options . tooltips . titleAlign ,
titleSpacing : options . tooltips . titleSpacing ,
titleMarginBottom : options . tooltips . titleMarginBottom ,
// Footer
footerColor : options . tooltips . footerColor ,
_footerFontFamily : helpers . getValueOrDefault ( options . tooltips . footerFontFamily , Chart . defaults . global . defaultFontFamily ) ,
_footerFontStyle : helpers . getValueOrDefault ( options . tooltips . footerFontStyle , Chart . defaults . global . defaultFontStyle ) ,
footerFontSize : helpers . getValueOrDefault ( options . tooltips . footerFontSize , Chart . defaults . global . defaultFontSize ) ,
_footerAlign : options . tooltips . footerAlign ,
footerSpacing : options . tooltips . footerSpacing ,
footerMarginTop : options . tooltips . footerMarginTop ,
// Appearance
caretSize : options . tooltips . caretSize ,
cornerRadius : options . tooltips . cornerRadius ,
backgroundColor : options . tooltips . backgroundColor ,
opacity : 0 ,
legendColorBackground : options . tooltips . multiKeyBackground
}
} ) ;
} ,
// Get the title
// Args are: (tooltipItem, data)
getTitle : function ( ) {
var beforeTitle = this . _options . tooltips . callbacks . beforeTitle . apply ( this , arguments ) ,
title = this . _options . tooltips . callbacks . title . apply ( this , arguments ) ,
afterTitle = this . _options . tooltips . callbacks . afterTitle . apply ( this , arguments ) ;
var lines = [ ] ;
lines = pushOrConcat ( lines , beforeTitle ) ;
lines = pushOrConcat ( lines , title ) ;
lines = pushOrConcat ( lines , afterTitle ) ;
return lines ;
} ,
// Args are: (tooltipItem, data)
getBeforeBody : function ( ) {
var lines = this . _options . tooltips . callbacks . beforeBody . apply ( this , arguments ) ;
return helpers . isArray ( lines ) ? lines : lines !== undefined ? [ lines ] : [ ] ;
} ,
// Args are: (tooltipItem, data)
getBody : function ( tooltipItems , data ) {
var lines = [ ] ;
helpers . each ( tooltipItems , function ( bodyItem ) {
helpers . pushAllIfDefined ( this . _options . tooltips . callbacks . beforeLabel . call ( this , bodyItem , data ) , lines ) ;
helpers . pushAllIfDefined ( this . _options . tooltips . callbacks . label . call ( this , bodyItem , data ) , lines ) ;
helpers . pushAllIfDefined ( this . _options . tooltips . callbacks . afterLabel . call ( this , bodyItem , data ) , lines ) ;
} , this ) ;
return lines ;
} ,
// Args are: (tooltipItem, data)
getAfterBody : function ( ) {
var lines = this . _options . tooltips . callbacks . afterBody . apply ( this , arguments ) ;
return helpers . isArray ( lines ) ? lines : lines !== undefined ? [ lines ] : [ ] ;
} ,
// Get the footer and beforeFooter and afterFooter lines
// Args are: (tooltipItem, data)
getFooter : function ( ) {
var beforeFooter = this . _options . tooltips . callbacks . beforeFooter . apply ( this , arguments ) ;
var footer = this . _options . tooltips . callbacks . footer . apply ( this , arguments ) ;
var afterFooter = this . _options . tooltips . callbacks . afterFooter . apply ( this , arguments ) ;
var lines = [ ] ;
lines = pushOrConcat ( lines , beforeFooter ) ;
lines = pushOrConcat ( lines , footer ) ;
lines = pushOrConcat ( lines , afterFooter ) ;
return lines ;
} ,
getAveragePosition : function ( elements ) {
if ( ! elements . length ) {
return false ;
}
var xPositions = [ ] ;
var yPositions = [ ] ;
helpers . each ( elements , function ( el ) {
if ( el ) {
var pos = el . tooltipPosition ( ) ;
xPositions . push ( pos . x ) ;
yPositions . push ( pos . y ) ;
}
} ) ;
var x = 0 ,
y = 0 ;
for ( var i = 0 ; i < xPositions . length ; i ++ ) {
x += xPositions [ i ] ;
y += yPositions [ i ] ;
}
return {
x : Math . round ( x / xPositions . length ) ,
y : Math . round ( y / xPositions . length )
} ;
} ,
update : function ( changed ) {
if ( this . _active . length ) {
this . _model . opacity = 1 ;
var element = this . _active [ 0 ] ,
labelColors = [ ] ,
tooltipPosition ;
var tooltipItems = [ ] ;
if ( this . _options . tooltips . mode === 'single' ) {
var yScale = element . _yScale || element . _scale ; // handle radar || polarArea charts
tooltipItems . push ( {
xLabel : element . _xScale ? element . _xScale . getLabelForIndex ( element . _index , element . _datasetIndex ) : '' ,
yLabel : yScale ? yScale . getLabelForIndex ( element . _index , element . _datasetIndex ) : '' ,
index : element . _index ,
datasetIndex : element . _datasetIndex
} ) ;
tooltipPosition = this . getAveragePosition ( this . _active ) ;
} else {
helpers . each ( this . _data . datasets , function ( dataset , datasetIndex ) {
if ( ! this . _chartInstance . isDatasetVisible ( datasetIndex ) ) {
return ;
}
var meta = this . _chartInstance . getDatasetMeta ( datasetIndex ) ;
var currentElement = meta . data [ element . _index ] ;
if ( currentElement ) {
var yScale = element . _yScale || element . _scale ; // handle radar || polarArea charts
tooltipItems . push ( {
xLabel : currentElement . _xScale ? currentElement . _xScale . getLabelForIndex ( currentElement . _index , currentElement . _datasetIndex ) : '' ,
yLabel : yScale ? yScale . getLabelForIndex ( currentElement . _index , currentElement . _datasetIndex ) : '' ,
index : element . _index ,
datasetIndex : datasetIndex
} ) ;
}
} , this ) ;
helpers . each ( this . _active , function ( active ) {
if ( active ) {
labelColors . push ( {
borderColor : active . _view . borderColor ,
backgroundColor : active . _view . backgroundColor
} ) ;
}
} , null ) ;
tooltipPosition = this . getAveragePosition ( this . _active ) ;
}
// Build the Text Lines
helpers . extend ( this . _model , {
title : this . getTitle ( tooltipItems , this . _data ) ,
beforeBody : this . getBeforeBody ( tooltipItems , this . _data ) ,
body : this . getBody ( tooltipItems , this . _data ) ,
afterBody : this . getAfterBody ( tooltipItems , this . _data ) ,
footer : this . getFooter ( tooltipItems , this . _data )
} ) ;
helpers . extend ( this . _model , {
x : Math . round ( tooltipPosition . x ) ,
y : Math . round ( tooltipPosition . y ) ,
caretPadding : helpers . getValueOrDefault ( tooltipPosition . padding , 2 ) ,
labelColors : labelColors
} ) ;
// We need to determine alignment of
var tooltipSize = this . getTooltipSize ( this . _model ) ;
this . determineAlignment ( tooltipSize ) ; // Smart Tooltip placement to stay on the canvas
helpers . extend ( this . _model , this . getBackgroundPoint ( this . _model , tooltipSize ) ) ;
} else {
this . _model . opacity = 0 ;
}
if ( changed && this . _options . tooltips . custom ) {
this . _options . tooltips . custom . call ( this , this . _model ) ;
}
return this ;
} ,
getTooltipSize : function getTooltipSize ( vm ) {
var ctx = this . _chart . ctx ;
var size = {
height : vm . yPadding * 2 , // Tooltip Padding
width : 0
} ;
var combinedBodyLength = vm . body . length + vm . beforeBody . length + vm . afterBody . length ;
size . height += vm . title . length * vm . titleFontSize ; // Title Lines
size . height += ( vm . title . length - 1 ) * vm . titleSpacing ; // Title Line Spacing
size . height += vm . title . length ? vm . titleMarginBottom : 0 ; // Title's bottom Margin
size . height += combinedBodyLength * vm . bodyFontSize ; // Body Lines
size . height += combinedBodyLength ? ( combinedBodyLength - 1 ) * vm . bodySpacing : 0 ; // Body Line Spacing
size . height += vm . footer . length ? vm . footerMarginTop : 0 ; // Footer Margin
size . height += vm . footer . length * ( vm . footerFontSize ) ; // Footer Lines
size . height += vm . footer . length ? ( vm . footer . length - 1 ) * vm . footerSpacing : 0 ; // Footer Line Spacing
// Width
ctx . font = helpers . fontString ( vm . titleFontSize , vm . _titleFontStyle , vm . _titleFontFamily ) ;
helpers . each ( vm . title , function ( line ) {
size . width = Math . max ( size . width , ctx . measureText ( line ) . width ) ;
} ) ;
ctx . font = helpers . fontString ( vm . bodyFontSize , vm . _bodyFontStyle , vm . _bodyFontFamily ) ;
helpers . each ( vm . beforeBody . concat ( vm . afterBody ) , function ( line ) {
size . width = Math . max ( size . width , ctx . measureText ( line ) . width ) ;
} ) ;
helpers . each ( vm . body , function ( line ) {
size . width = Math . max ( size . width , ctx . measureText ( line ) . width + ( this . _options . tooltips . mode !== 'single' ? ( vm . bodyFontSize + 2 ) : 0 ) ) ;
} , this ) ;
ctx . font = helpers . fontString ( vm . footerFontSize , vm . _footerFontStyle , vm . _footerFontFamily ) ;
helpers . each ( vm . footer , function ( line ) {
size . width = Math . max ( size . width , ctx . measureText ( line ) . width ) ;
} ) ;
size . width += 2 * vm . xPadding ;
return size ;
} ,
determineAlignment : function determineAlignment ( size ) {
if ( this . _model . y < size . height ) {
this . _model . yAlign = 'top' ;
} else if ( this . _model . y > ( this . _chart . height - size . height ) ) {
this . _model . yAlign = 'bottom' ;
}
var lf , rf ; // functions to determine left, right alignment
var olf , orf ; // functions to determine if left/right alignment causes tooltip to go outside chart
var yf ; // function to get the y alignment if the tooltip goes outside of the left or right edges
var _this = this ;
var midX = ( this . _chartInstance . chartArea . left + this . _chartInstance . chartArea . right ) / 2 ;
var midY = ( this . _chartInstance . chartArea . top + this . _chartInstance . chartArea . bottom ) / 2 ;
if ( this . _model . yAlign === 'center' ) {
lf = function ( x ) {
return x <= midX ;
} ;
rf = function ( x ) {
return x > midX ;
} ;
} else {
lf = function ( x ) {
return x <= ( size . width / 2 ) ;
} ;
rf = function ( x ) {
return x >= ( _this . _chart . width - ( size . width / 2 ) ) ;
} ;
}
olf = function ( x ) {
return x + size . width > _this . _chart . width ;
} ;
orf = function ( x ) {
return x - size . width < 0 ;
} ;
yf = function ( y ) {
return y <= midY ? 'top' : 'bottom' ;
} ;
if ( lf ( this . _model . x ) ) {
this . _model . xAlign = 'left' ;
// Is tooltip too wide and goes over the right side of the chart.?
if ( olf ( this . _model . x ) ) {
this . _model . xAlign = 'center' ;
this . _model . yAlign = yf ( this . _model . y ) ;
}
} else if ( rf ( this . _model . x ) ) {
this . _model . xAlign = 'right' ;
// Is tooltip too wide and goes outside left edge of canvas?
if ( orf ( this . _model . x ) ) {
this . _model . xAlign = 'center' ;
this . _model . yAlign = yf ( this . _model . y ) ;
}
}
} ,
getBackgroundPoint : function getBackgroundPoint ( vm , size ) {
// Background Position
var pt = {
x : vm . x ,
y : vm . y
} ;
if ( vm . xAlign === 'right' ) {
pt . x -= size . width ;
} else if ( vm . xAlign === 'center' ) {
pt . x -= ( size . width / 2 ) ;
}
if ( vm . yAlign === 'top' ) {
pt . y += vm . caretPadding + vm . caretSize ;
} else if ( vm . yAlign === 'bottom' ) {
pt . y -= size . height + vm . caretPadding + vm . caretSize ;
} else {
pt . y -= ( size . height / 2 ) ;
}
if ( vm . yAlign === 'center' ) {
if ( vm . xAlign === 'left' ) {
pt . x += vm . caretPadding + vm . caretSize ;
} else if ( vm . xAlign === 'right' ) {
pt . x -= vm . caretPadding + vm . caretSize ;
}
} else {
if ( vm . xAlign === 'left' ) {
pt . x -= vm . cornerRadius + vm . caretPadding ;
} else if ( vm . xAlign === 'right' ) {
pt . x += vm . cornerRadius + vm . caretPadding ;
}
}
return pt ;
} ,
drawCaret : function drawCaret ( tooltipPoint , size , opacity , caretPadding ) {
var vm = this . _view ;
var ctx = this . _chart . ctx ;
var x1 , x2 , x3 ;
var y1 , y2 , y3 ;
if ( vm . yAlign === 'center' ) {
// Left or right side
if ( vm . xAlign === 'left' ) {
x1 = tooltipPoint . x ;
x2 = x1 - vm . caretSize ;
x3 = x1 ;
} else {
x1 = tooltipPoint . x + size . width ;
x2 = x1 + vm . caretSize ;
x3 = x1 ;
}
y2 = tooltipPoint . y + ( size . height / 2 ) ;
y1 = y2 - vm . caretSize ;
y3 = y2 + vm . caretSize ;
} else {
if ( vm . xAlign === 'left' ) {
x1 = tooltipPoint . x + vm . cornerRadius ;
x2 = x1 + vm . caretSize ;
x3 = x2 + vm . caretSize ;
} else if ( vm . xAlign === 'right' ) {
x1 = tooltipPoint . x + size . width - vm . cornerRadius ;
x2 = x1 - vm . caretSize ;
x3 = x2 - vm . caretSize ;
} else {
x2 = tooltipPoint . x + ( size . width / 2 ) ;
x1 = x2 - vm . caretSize ;
x3 = x2 + vm . caretSize ;
}
if ( vm . yAlign === 'top' ) {
y1 = tooltipPoint . y ;
y2 = y1 - vm . caretSize ;
y3 = y1 ;
} else {
y1 = tooltipPoint . y + size . height ;
y2 = y1 + vm . caretSize ;
y3 = y1 ;
}
}
var bgColor = helpers . color ( vm . backgroundColor ) ;
ctx . fillStyle = bgColor . alpha ( opacity * bgColor . alpha ( ) ) . rgbString ( ) ;
ctx . beginPath ( ) ;
ctx . moveTo ( x1 , y1 ) ;
ctx . lineTo ( x2 , y2 ) ;
ctx . lineTo ( x3 , y3 ) ;
ctx . closePath ( ) ;
ctx . fill ( ) ;
} ,
drawTitle : function drawTitle ( pt , vm , ctx , opacity ) {
if ( vm . title . length ) {
ctx . textAlign = vm . _titleAlign ;
ctx . textBaseline = "top" ;
var titleColor = helpers . color ( vm . titleColor ) ;
ctx . fillStyle = titleColor . alpha ( opacity * titleColor . alpha ( ) ) . rgbString ( ) ;
ctx . font = helpers . fontString ( vm . titleFontSize , vm . _titleFontStyle , vm . _titleFontFamily ) ;
helpers . each ( vm . title , function ( title , i ) {
ctx . fillText ( title , pt . x , pt . y ) ;
pt . y += vm . titleFontSize + vm . titleSpacing ; // Line Height and spacing
if ( i + 1 === vm . title . length ) {
pt . y += vm . titleMarginBottom - vm . titleSpacing ; // If Last, add margin, remove spacing
}
} ) ;
}
} ,
drawBody : function drawBody ( pt , vm , ctx , opacity ) {
ctx . textAlign = vm . _bodyAlign ;
ctx . textBaseline = "top" ;
var bodyColor = helpers . color ( vm . bodyColor ) ;
ctx . fillStyle = bodyColor . alpha ( opacity * bodyColor . alpha ( ) ) . rgbString ( ) ;
ctx . font = helpers . fontString ( vm . bodyFontSize , vm . _bodyFontStyle , vm . _bodyFontFamily ) ;
// Before Body
helpers . each ( vm . beforeBody , function ( beforeBody ) {
ctx . fillText ( beforeBody , pt . x , pt . y ) ;
pt . y += vm . bodyFontSize + vm . bodySpacing ;
} ) ;
helpers . each ( vm . body , function ( body , i ) {
// Draw Legend-like boxes if needed
if ( this . _options . tooltips . mode !== 'single' ) {
// Fill a white rect so that colours merge nicely if the opacity is < 1
ctx . fillStyle = helpers . color ( vm . legendColorBackground ) . alpha ( opacity ) . rgbaString ( ) ;
ctx . fillRect ( pt . x , pt . y , vm . bodyFontSize , vm . bodyFontSize ) ;
// Border
ctx . strokeStyle = helpers . color ( vm . labelColors [ i ] . borderColor ) . alpha ( opacity ) . rgbaString ( ) ;
ctx . strokeRect ( pt . x , pt . y , vm . bodyFontSize , vm . bodyFontSize ) ;
// Inner square
ctx . fillStyle = helpers . color ( vm . labelColors [ i ] . backgroundColor ) . alpha ( opacity ) . rgbaString ( ) ;
ctx . fillRect ( pt . x + 1 , pt . y + 1 , vm . bodyFontSize - 2 , vm . bodyFontSize - 2 ) ;
ctx . fillStyle = helpers . color ( vm . bodyColor ) . alpha ( opacity ) . rgbaString ( ) ; // Return fill style for text
}
// Body Line
ctx . fillText ( body , pt . x + ( this . _options . tooltips . mode !== 'single' ? ( vm . bodyFontSize + 2 ) : 0 ) , pt . y ) ;
pt . y += vm . bodyFontSize + vm . bodySpacing ;
} , this ) ;
// After Body
helpers . each ( vm . afterBody , function ( afterBody ) {
ctx . fillText ( afterBody , pt . x , pt . y ) ;
pt . y += vm . bodyFontSize ;
} ) ;
pt . y -= vm . bodySpacing ; // Remove last body spacing
} ,
drawFooter : function drawFooter ( pt , vm , ctx , opacity ) {
if ( vm . footer . length ) {
pt . y += vm . footerMarginTop ;
ctx . textAlign = vm . _footerAlign ;
ctx . textBaseline = "top" ;
var footerColor = helpers . color ( vm . footerColor ) ;
ctx . fillStyle = footerColor . alpha ( opacity * footerColor . alpha ( ) ) . rgbString ( ) ;
ctx . font = helpers . fontString ( vm . footerFontSize , vm . _footerFontStyle , vm . _footerFontFamily ) ;
helpers . each ( vm . footer , function ( footer ) {
ctx . fillText ( footer , pt . x , pt . y ) ;
pt . y += vm . footerFontSize + vm . footerSpacing ;
} ) ;
}
} ,
draw : function draw ( ) {
var ctx = this . _chart . ctx ;
var vm = this . _view ;
if ( vm . opacity === 0 ) {
return ;
}
var caretPadding = vm . caretPadding ;
var tooltipSize = this . getTooltipSize ( vm ) ;
var pt = {
x : vm . x ,
y : vm . y
} ;
// IE11/Edge does not like very small opacities, so snap to 0
var opacity = Math . abs ( vm . opacity < 1e-3 ) ? 0 : vm . opacity ;
if ( this . _options . tooltips . enabled ) {
// Draw Background
var bgColor = helpers . color ( vm . backgroundColor ) ;
ctx . fillStyle = bgColor . alpha ( opacity * bgColor . alpha ( ) ) . rgbString ( ) ;
helpers . drawRoundedRectangle ( ctx , pt . x , pt . y , tooltipSize . width , tooltipSize . height , vm . cornerRadius ) ;
ctx . fill ( ) ;
// Draw Caret
this . drawCaret ( pt , tooltipSize , opacity , caretPadding ) ;
// Draw Title, Body, and Footer
pt . x += vm . xPadding ;
pt . y += vm . yPadding ;
// Titles
this . drawTitle ( pt , vm , ctx , opacity ) ;
// Body
this . drawBody ( pt , vm , ctx , opacity ) ;
// Footer
this . drawFooter ( pt , vm , ctx , opacity ) ;
}
}
} ) ;
} ;
} , { } ] , 34 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart , moment ) {
var helpers = Chart . helpers ,
globalOpts = Chart . defaults . global ;
globalOpts . elements . arc = {
backgroundColor : globalOpts . defaultColor ,
borderColor : "#fff" ,
borderWidth : 2
} ;
Chart . elements . Arc = Chart . Element . extend ( {
inLabelRange : function ( mouseX ) {
var vm = this . _view ;
if ( vm ) {
return ( Math . pow ( mouseX - vm . x , 2 ) < Math . pow ( vm . radius + vm . hoverRadius , 2 ) ) ;
} else {
return false ;
}
} ,
inRange : function ( chartX , chartY ) {
var vm = this . _view ;
if ( vm ) {
var pointRelativePosition = helpers . getAngleFromPoint ( vm , {
x : chartX ,
y : chartY
} ) ,
angle = pointRelativePosition . angle ,
distance = pointRelativePosition . distance ;
//Sanitise angle range
var startAngle = vm . startAngle ;
var endAngle = vm . endAngle ;
while ( endAngle < startAngle ) {
endAngle += 2.0 * Math . PI ;
}
while ( angle > endAngle ) {
angle -= 2.0 * Math . PI ;
}
while ( angle < startAngle ) {
angle += 2.0 * Math . PI ;
}
//Check if within the range of the open/close angle
var betweenAngles = ( angle >= startAngle && angle <= endAngle ) ,
withinRadius = ( distance >= vm . innerRadius && distance <= vm . outerRadius ) ;
return ( betweenAngles && withinRadius ) ;
} else {
return false ;
}
} ,
tooltipPosition : function ( ) {
var vm = this . _view ;
var centreAngle = vm . startAngle + ( ( vm . endAngle - vm . startAngle ) / 2 ) ,
rangeFromCentre = ( vm . outerRadius - vm . innerRadius ) / 2 + vm . innerRadius ;
return {
x : vm . x + ( Math . cos ( centreAngle ) * rangeFromCentre ) ,
y : vm . y + ( Math . sin ( centreAngle ) * rangeFromCentre )
} ;
} ,
draw : function ( ) {
var ctx = this . _chart . ctx ,
vm = this . _view ,
sA = vm . startAngle ,
eA = vm . endAngle ;
ctx . beginPath ( ) ;
ctx . arc ( vm . x , vm . y , vm . outerRadius , sA , eA ) ;
ctx . arc ( vm . x , vm . y , vm . innerRadius , eA , sA , true ) ;
ctx . closePath ( ) ;
ctx . strokeStyle = vm . borderColor ;
ctx . lineWidth = vm . borderWidth ;
ctx . fillStyle = vm . backgroundColor ;
ctx . fill ( ) ;
ctx . lineJoin = 'bevel' ;
if ( vm . borderWidth ) {
ctx . stroke ( ) ;
}
}
} ) ;
} ;
} , { } ] , 35 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
Chart . defaults . global . elements . line = {
tension : 0.4 ,
backgroundColor : Chart . defaults . global . defaultColor ,
borderWidth : 3 ,
borderColor : Chart . defaults . global . defaultColor ,
borderCapStyle : 'butt' ,
borderDash : [ ] ,
borderDashOffset : 0.0 ,
borderJoinStyle : 'miter' ,
fill : true // do we fill in the area between the line and its base axis
} ;
Chart . elements . Line = Chart . Element . extend ( {
lineToNextPoint : function ( previousPoint , point , nextPoint , skipHandler , previousSkipHandler ) {
var ctx = this . _chart . ctx ;
if ( point . _view . skip ) {
skipHandler . call ( this , previousPoint , point , nextPoint ) ;
} else if ( previousPoint . _view . skip ) {
previousSkipHandler . call ( this , previousPoint , point , nextPoint ) ;
} else if ( point . _view . tension === 0 ) {
ctx . lineTo ( point . _view . x , point . _view . y ) ;
} else {
// Line between points
ctx . bezierCurveTo (
previousPoint . _view . controlPointNextX ,
previousPoint . _view . controlPointNextY ,
point . _view . controlPointPreviousX ,
point . _view . controlPointPreviousY ,
point . _view . x ,
point . _view . y
) ;
}
} ,
draw : function ( ) {
var _this = this ;
var vm = this . _view ;
var ctx = this . _chart . ctx ;
var first = this . _children [ 0 ] ;
var last = this . _children [ this . _children . length - 1 ] ;
function loopBackToStart ( drawLineToCenter ) {
if ( ! first . _view . skip && ! last . _view . skip ) {
// Draw a bezier line from last to first
ctx . bezierCurveTo (
last . _view . controlPointNextX ,
last . _view . controlPointNextY ,
first . _view . controlPointPreviousX ,
first . _view . controlPointPreviousY ,
first . _view . x ,
first . _view . y
) ;
} else if ( drawLineToCenter ) {
// Go to center
ctx . lineTo ( _this . _view . scaleZero . x , _this . _view . scaleZero . y ) ;
}
}
ctx . save ( ) ;
// If we had points and want to fill this line, do so.
if ( this . _children . length > 0 && vm . fill ) {
// Draw the background first (so the border is always on top)
ctx . beginPath ( ) ;
helpers . each ( this . _children , function ( point , index ) {
var previous = helpers . previousItem ( this . _children , index ) ;
var next = helpers . nextItem ( this . _children , index ) ;
// First point moves to it's starting position no matter what
if ( index === 0 ) {
if ( this . _loop ) {
ctx . moveTo ( vm . scaleZero . x , vm . scaleZero . y ) ;
} else {
ctx . moveTo ( point . _view . x , vm . scaleZero ) ;
}
if ( point . _view . skip ) {
if ( ! this . _loop ) {
ctx . moveTo ( next . _view . x , this . _view . scaleZero ) ;
}
} else {
ctx . lineTo ( point . _view . x , point . _view . y ) ;
}
} else {
this . lineToNextPoint ( previous , point , next , function ( previousPoint , point , nextPoint ) {
if ( this . _loop ) {
// Go to center
ctx . lineTo ( this . _view . scaleZero . x , this . _view . scaleZero . y ) ;
} else {
ctx . lineTo ( previousPoint . _view . x , this . _view . scaleZero ) ;
ctx . moveTo ( nextPoint . _view . x , this . _view . scaleZero ) ;
}
} , function ( previousPoint , point ) {
// If we skipped the last point, draw a line to ourselves so that the fill is nice
ctx . lineTo ( point . _view . x , point . _view . y ) ;
} ) ;
}
} , this ) ;
// For radial scales, loop back around to the first point
if ( this . _loop ) {
loopBackToStart ( true ) ;
} else {
//Round off the line by going to the base of the chart, back to the start, then fill.
ctx . lineTo ( this . _children [ this . _children . length - 1 ] . _view . x , vm . scaleZero ) ;
ctx . lineTo ( this . _children [ 0 ] . _view . x , vm . scaleZero ) ;
}
ctx . fillStyle = vm . backgroundColor || Chart . defaults . global . defaultColor ;
ctx . closePath ( ) ;
ctx . fill ( ) ;
}
// Now draw the line between all the points with any borders
ctx . lineCap = vm . borderCapStyle || Chart . defaults . global . elements . line . borderCapStyle ;
// IE 9 and 10 do not support line dash
if ( ctx . setLineDash ) {
ctx . setLineDash ( vm . borderDash || Chart . defaults . global . elements . line . borderDash ) ;
}
ctx . lineDashOffset = vm . borderDashOffset || Chart . defaults . global . elements . line . borderDashOffset ;
ctx . lineJoin = vm . borderJoinStyle || Chart . defaults . global . elements . line . borderJoinStyle ;
ctx . lineWidth = vm . borderWidth || Chart . defaults . global . elements . line . borderWidth ;
ctx . strokeStyle = vm . borderColor || Chart . defaults . global . defaultColor ;
ctx . beginPath ( ) ;
helpers . each ( this . _children , function ( point , index ) {
var previous = helpers . previousItem ( this . _children , index ) ;
var next = helpers . nextItem ( this . _children , index ) ;
if ( index === 0 ) {
ctx . moveTo ( point . _view . x , point . _view . y ) ;
} else {
this . lineToNextPoint ( previous , point , next , function ( previousPoint , point , nextPoint ) {
ctx . moveTo ( nextPoint . _view . x , nextPoint . _view . y ) ;
} , function ( previousPoint , point ) {
// If we skipped the last point, move up to our point preventing a line from being drawn
ctx . moveTo ( point . _view . x , point . _view . y ) ;
} ) ;
}
} , this ) ;
if ( this . _loop && this . _children . length > 0 ) {
loopBackToStart ( ) ;
}
ctx . stroke ( ) ;
ctx . restore ( ) ;
}
} ) ;
} ;
} , { } ] , 36 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ,
globalOpts = Chart . defaults . global ;
globalOpts . elements . point = {
radius : 3 ,
pointStyle : 'circle' ,
backgroundColor : globalOpts . defaultColor ,
borderWidth : 1 ,
borderColor : globalOpts . defaultColor ,
// Hover
hitRadius : 1 ,
hoverRadius : 4 ,
hoverBorderWidth : 1
} ;
Chart . elements . Point = Chart . Element . extend ( {
inRange : function ( mouseX , mouseY ) {
var vm = this . _view ;
return vm ? ( ( Math . pow ( mouseX - vm . x , 2 ) + Math . pow ( mouseY - vm . y , 2 ) ) < Math . pow ( vm . hitRadius + vm . radius , 2 ) ) : false ;
} ,
inLabelRange : function ( mouseX ) {
var vm = this . _view ;
return vm ? ( Math . pow ( mouseX - vm . x , 2 ) < Math . pow ( vm . radius + vm . hitRadius , 2 ) ) : false ;
} ,
tooltipPosition : function ( ) {
var vm = this . _view ;
return {
x : vm . x ,
y : vm . y ,
padding : vm . radius + vm . borderWidth
} ;
} ,
draw : function ( ) {
var vm = this . _view ,
x = vm . x ,
y = vm . y ;
var ctx = this . _chart . ctx ;
if ( vm . skip ) {
return ;
}
var pointStyle = vm . pointStyle ;
if ( typeof pointStyle === 'object' && ( ( pointStyle . toString ( ) === '[object HTMLImageElement]' ) || ( pointStyle . toString ( ) === '[object HTMLCanvasElement]' ) ) ) {
ctx . drawImage ( pointStyle , x - pointStyle . width / 2 , y - pointStyle . height / 2 ) ;
return ;
}
if ( ! isNaN ( vm . radius ) && vm . radius > 0 ) {
ctx . strokeStyle = vm . borderColor || Chart . defaults . global . defaultColor ;
ctx . lineWidth = helpers . getValueOrDefault ( vm . borderWidth , Chart . defaults . global . elements . point . borderWidth ) ;
ctx . fillStyle = vm . backgroundColor || Chart . defaults . global . defaultColor ;
var radius = vm . radius ;
var xOffset ,
yOffset ;
switch ( pointStyle ) {
// Default includes circle
default :
ctx . beginPath ( ) ;
ctx . arc ( x , y , radius , 0 , Math . PI * 2 ) ;
ctx . closePath ( ) ;
ctx . fill ( ) ;
break ;
case 'triangle' :
ctx . beginPath ( ) ;
var edgeLength = 3 * radius / Math . sqrt ( 3 ) ;
var height = edgeLength * Math . sqrt ( 3 ) / 2 ;
ctx . moveTo ( x - edgeLength / 2 , y + height / 3 ) ;
ctx . lineTo ( x + edgeLength / 2 , y + height / 3 ) ;
ctx . lineTo ( x , y - 2 * height / 3 ) ;
ctx . closePath ( ) ;
ctx . fill ( ) ;
break ;
case 'rect' :
ctx . fillRect ( x - 1 / Math . SQRT2 * radius , y - 1 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius ) ;
ctx . strokeRect ( x - 1 / Math . SQRT2 * radius , y - 1 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius ) ;
break ;
case 'rectRot' :
ctx . translate ( x , y ) ;
ctx . rotate ( Math . PI / 4 ) ;
ctx . fillRect ( - 1 / Math . SQRT2 * radius , - 1 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius ) ;
ctx . strokeRect ( - 1 / Math . SQRT2 * radius , - 1 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius , 2 / Math . SQRT2 * radius ) ;
ctx . setTransform ( 1 , 0 , 0 , 1 , 0 , 0 ) ;
break ;
case 'cross' :
ctx . beginPath ( ) ;
ctx . moveTo ( x , y + radius ) ;
ctx . lineTo ( x , y - radius ) ;
ctx . moveTo ( x - radius , y ) ;
ctx . lineTo ( x + radius , y ) ;
ctx . closePath ( ) ;
break ;
case 'crossRot' :
ctx . beginPath ( ) ;
xOffset = Math . cos ( Math . PI / 4 ) * radius ;
yOffset = Math . sin ( Math . PI / 4 ) * radius ;
ctx . moveTo ( x - xOffset , y - yOffset ) ;
ctx . lineTo ( x + xOffset , y + yOffset ) ;
ctx . moveTo ( x - xOffset , y + yOffset ) ;
ctx . lineTo ( x + xOffset , y - yOffset ) ;
ctx . closePath ( ) ;
break ;
case 'star' :
ctx . beginPath ( ) ;
ctx . moveTo ( x , y + radius ) ;
ctx . lineTo ( x , y - radius ) ;
ctx . moveTo ( x - radius , y ) ;
ctx . lineTo ( x + radius , y ) ;
xOffset = Math . cos ( Math . PI / 4 ) * radius ;
yOffset = Math . sin ( Math . PI / 4 ) * radius ;
ctx . moveTo ( x - xOffset , y - yOffset ) ;
ctx . lineTo ( x + xOffset , y + yOffset ) ;
ctx . moveTo ( x - xOffset , y + yOffset ) ;
ctx . lineTo ( x + xOffset , y - yOffset ) ;
ctx . closePath ( ) ;
break ;
case 'line' :
ctx . beginPath ( ) ;
ctx . moveTo ( x - radius , y ) ;
ctx . lineTo ( x + radius , y ) ;
ctx . closePath ( ) ;
break ;
case 'dash' :
ctx . beginPath ( ) ;
ctx . moveTo ( x , y ) ;
ctx . lineTo ( x + radius , y ) ;
ctx . closePath ( ) ;
break ;
}
ctx . stroke ( ) ;
}
}
} ) ;
} ;
} , { } ] , 37 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ,
globalOpts = Chart . defaults . global ;
globalOpts . elements . rectangle = {
backgroundColor : globalOpts . defaultColor ,
borderWidth : 0 ,
borderColor : globalOpts . defaultColor ,
borderSkipped : 'bottom'
} ;
Chart . elements . Rectangle = Chart . Element . extend ( {
draw : function ( ) {
var ctx = this . _chart . ctx ;
var vm = this . _view ;
var halfWidth = vm . width / 2 ,
leftX = vm . x - halfWidth ,
rightX = vm . x + halfWidth ,
top = vm . base - ( vm . base - vm . y ) ,
halfStroke = vm . borderWidth / 2 ;
// Canvas doesn't allow us to stroke inside the width so we can
// adjust the sizes to fit if we're setting a stroke on the line
if ( vm . borderWidth ) {
leftX += halfStroke ;
rightX -= halfStroke ;
top += halfStroke ;
}
ctx . beginPath ( ) ;
ctx . fillStyle = vm . backgroundColor ;
ctx . strokeStyle = vm . borderColor ;
ctx . lineWidth = vm . borderWidth ;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
var corners = [
[ leftX , vm . base ] ,
[ leftX , top ] ,
[ rightX , top ] ,
[ rightX , vm . base ]
] ;
// Find first (starting) corner with fallback to 'bottom'
var borders = [ 'bottom' , 'left' , 'top' , 'right' ] ;
var startCorner = borders . indexOf ( vm . borderSkipped , 0 ) ;
if ( startCorner === - 1 )
startCorner = 0 ;
function cornerAt ( index ) {
return corners [ ( startCorner + index ) % 4 ] ;
}
// Draw rectangle from 'startCorner'
ctx . moveTo . apply ( ctx , cornerAt ( 0 ) ) ;
for ( var i = 1 ; i < 4 ; i ++ )
ctx . lineTo . apply ( ctx , cornerAt ( i ) ) ;
ctx . fill ( ) ;
if ( vm . borderWidth ) {
ctx . stroke ( ) ;
}
} ,
height : function ( ) {
var vm = this . _view ;
return vm . base - vm . y ;
} ,
inRange : function ( mouseX , mouseY ) {
var vm = this . _view ;
return vm ?
( vm . y < vm . base ?
( mouseX >= vm . x - vm . width / 2 && mouseX <= vm . x + vm . width / 2 ) && ( mouseY >= vm . y && mouseY <= vm . base ) :
( mouseX >= vm . x - vm . width / 2 && mouseX <= vm . x + vm . width / 2 ) && ( mouseY >= vm . base && mouseY <= vm . y ) ) :
false ;
} ,
inLabelRange : function ( mouseX ) {
var vm = this . _view ;
return vm ? ( mouseX >= vm . x - vm . width / 2 && mouseX <= vm . x + vm . width / 2 ) : false ;
} ,
tooltipPosition : function ( ) {
var vm = this . _view ;
return {
x : vm . x ,
y : vm . y
} ;
}
} ) ;
} ;
} , { } ] , 38 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
// Default config for a category scale
var defaultConfig = {
position : "bottom"
} ;
var DatasetScale = Chart . Scale . extend ( {
// Implement this so that
determineDataLimits : function ( ) {
this . minIndex = 0 ;
this . maxIndex = this . chart . data . labels . length - 1 ;
var findIndex ;
if ( this . options . ticks . min !== undefined ) {
// user specified min value
findIndex = helpers . indexOf ( this . chart . data . labels , this . options . ticks . min ) ;
this . minIndex = findIndex !== - 1 ? findIndex : this . minIndex ;
}
if ( this . options . ticks . max !== undefined ) {
// user specified max value
findIndex = helpers . indexOf ( this . chart . data . labels , this . options . ticks . max ) ;
this . maxIndex = findIndex !== - 1 ? findIndex : this . maxIndex ;
}
this . min = this . chart . data . labels [ this . minIndex ] ;
this . max = this . chart . data . labels [ this . maxIndex ] ;
} ,
buildTicks : function ( index ) {
// If we are viewing some subset of labels, slice the original array
this . ticks = ( this . minIndex === 0 && this . maxIndex === this . chart . data . labels . length - 1 ) ? this . chart . data . labels : this . chart . data . labels . slice ( this . minIndex , this . maxIndex + 1 ) ;
} ,
getLabelForIndex : function ( index , datasetIndex ) {
return this . ticks [ index ] ;
} ,
// Used to get data value locations. Value can either be an index or a numerical value
getPixelForValue : function ( value , index , datasetIndex , includeOffset ) {
// 1 is added because we need the length but we have the indexes
var offsetAmt = Math . max ( ( this . maxIndex + 1 - this . minIndex - ( ( this . options . gridLines . offsetGridLines ) ? 0 : 1 ) ) , 1 ) ;
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
var valueWidth = innerWidth / offsetAmt ;
var widthOffset = ( valueWidth * ( index - this . minIndex ) ) + this . paddingLeft ;
if ( this . options . gridLines . offsetGridLines && includeOffset ) {
widthOffset += ( valueWidth / 2 ) ;
}
return this . left + Math . round ( widthOffset ) ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
var valueHeight = innerHeight / offsetAmt ;
var heightOffset = ( valueHeight * ( index - this . minIndex ) ) + this . paddingTop ;
if ( this . options . gridLines . offsetGridLines && includeOffset ) {
heightOffset += ( valueHeight / 2 ) ;
}
return this . top + Math . round ( heightOffset ) ;
}
} ,
getPixelForTick : function ( index , includeOffset ) {
return this . getPixelForValue ( this . ticks [ index ] , index + this . minIndex , null , includeOffset ) ;
} ,
getValueForPixel : function ( pixel ) {
var value
; var offsetAmt = Math . max ( ( this . ticks . length - ( ( this . options . gridLines . offsetGridLines ) ? 0 : 1 ) ) , 1 ) ;
var horz = this . isHorizontal ( ) ;
var innerDimension = horz ? this . width - ( this . paddingLeft + this . paddingRight ) : this . height - ( this . paddingTop + this . paddingBottom ) ;
var valueDimension = innerDimension / offsetAmt ;
if ( this . options . gridLines . offsetGridLines ) {
pixel -= ( valueDimension / 2 ) ;
}
pixel -= horz ? this . paddingLeft : this . paddingTop ;
if ( pixel <= 0 ) {
value = 0 ;
} else {
value = Math . round ( pixel / valueDimension ) ;
}
return value ;
}
} ) ;
Chart . scaleService . registerScaleType ( "category" , DatasetScale , defaultConfig ) ;
} ;
} , { } ] , 39 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var defaultConfig = {
position : "left" ,
ticks : {
callback : function ( tickValue , index , ticks ) {
// If we have lots of ticks, don't use the ones
var delta = ticks . length > 3 ? ticks [ 2 ] - ticks [ 1 ] : ticks [ 1 ] - ticks [ 0 ] ;
// If we have a number like 2.5 as the delta, figure out how many decimal places we need
if ( Math . abs ( delta ) > 1 ) {
if ( tickValue !== Math . floor ( tickValue ) ) {
// not an integer
delta = tickValue - Math . floor ( tickValue ) ;
}
}
var logDelta = helpers . log10 ( Math . abs ( delta ) ) ;
var tickString = '' ;
if ( tickValue !== 0 ) {
var numDecimal = - 1 * Math . floor ( logDelta ) ;
numDecimal = Math . max ( Math . min ( numDecimal , 20 ) , 0 ) ; // toFixed has a max of 20 decimal places
tickString = tickValue . toFixed ( numDecimal ) ;
} else {
tickString = '0' ; // never show decimal places for 0
}
return tickString ;
}
}
} ;
var LinearScale = Chart . Scale . extend ( {
determineDataLimits : function ( ) {
// First Calculate the range
this . min = null ;
this . max = null ;
if ( this . options . stacked ) {
var valuesPerType = { } ;
var hasPositiveValues = false ;
var hasNegativeValues = false ;
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
var meta = this . chart . getDatasetMeta ( datasetIndex ) ;
if ( valuesPerType [ meta . type ] === undefined ) {
valuesPerType [ meta . type ] = {
positiveValues : [ ] ,
negativeValues : [ ]
} ;
}
// Store these per type
var positiveValues = valuesPerType [ meta . type ] . positiveValues ;
var negativeValues = valuesPerType [ meta . type ] . negativeValues ;
if ( this . chart . isDatasetVisible ( datasetIndex ) && ( this . isHorizontal ( ) ? meta . xAxisID === this . id : meta . yAxisID === this . id ) ) {
helpers . each ( dataset . data , function ( rawValue , index ) {
var value = + this . getRightValue ( rawValue ) ;
if ( isNaN ( value ) || meta . data [ index ] . hidden ) {
return ;
}
positiveValues [ index ] = positiveValues [ index ] || 0 ;
negativeValues [ index ] = negativeValues [ index ] || 0 ;
if ( this . options . relativePoints ) {
positiveValues [ index ] = 100 ;
} else {
if ( value < 0 ) {
hasNegativeValues = true ;
negativeValues [ index ] += value ;
} else {
hasPositiveValues = true ;
positiveValues [ index ] += value ;
}
}
} , this ) ;
}
} , this ) ;
helpers . each ( valuesPerType , function ( valuesForType ) {
var values = valuesForType . positiveValues . concat ( valuesForType . negativeValues ) ;
var minVal = helpers . min ( values ) ;
var maxVal = helpers . max ( values ) ;
this . min = this . min === null ? minVal : Math . min ( this . min , minVal ) ;
this . max = this . max === null ? maxVal : Math . max ( this . max , maxVal ) ;
} , this ) ;
} else {
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
var meta = this . chart . getDatasetMeta ( datasetIndex ) ;
if ( this . chart . isDatasetVisible ( datasetIndex ) && ( this . isHorizontal ( ) ? meta . xAxisID === this . id : meta . yAxisID === this . id ) ) {
helpers . each ( dataset . data , function ( rawValue , index ) {
var value = + this . getRightValue ( rawValue ) ;
if ( isNaN ( value ) || meta . data [ index ] . hidden ) {
return ;
}
if ( this . min === null ) {
this . min = value ;
} else if ( value < this . min ) {
this . min = value ;
}
if ( this . max === null ) {
this . max = value ;
} else if ( value > this . max ) {
this . max = value ;
}
} , this ) ;
}
} , this ) ;
}
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
// do nothing since that would make the chart weird. If the user really wants a weird chart
// axis, they can manually override it
if ( this . options . ticks . beginAtZero ) {
var minSign = helpers . sign ( this . min ) ;
var maxSign = helpers . sign ( this . max ) ;
if ( minSign < 0 && maxSign < 0 ) {
// move the top up to 0
this . max = 0 ;
} else if ( minSign > 0 && maxSign > 0 ) {
// move the botttom down to 0
this . min = 0 ;
}
}
if ( this . options . ticks . min !== undefined ) {
this . min = this . options . ticks . min ;
} else if ( this . options . ticks . suggestedMin !== undefined ) {
this . min = Math . min ( this . min , this . options . ticks . suggestedMin ) ;
}
if ( this . options . ticks . max !== undefined ) {
this . max = this . options . ticks . max ;
} else if ( this . options . ticks . suggestedMax !== undefined ) {
this . max = Math . max ( this . max , this . options . ticks . suggestedMax ) ;
}
if ( this . min === this . max ) {
this . max ++ ;
if ( ! this . options . ticks . beginAtZero ) {
this . min -- ;
}
}
} ,
buildTicks : function ( ) {
// Then calulate the ticks
this . ticks = [ ] ;
// Figure out what the max number of ticks we can support it is based on the size of
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
// the graph
var maxTicks ;
if ( this . isHorizontal ( ) ) {
maxTicks = Math . min ( this . options . ticks . maxTicksLimit ? this . options . ticks . maxTicksLimit : 11 , Math . ceil ( this . width / 50 ) ) ;
} else {
// The factor of 2 used to scale the font size has been experimentally determined.
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
maxTicks = Math . min ( this . options . ticks . maxTicksLimit ? this . options . ticks . maxTicksLimit : 11 , Math . ceil ( this . height / ( 2 * tickFontSize ) ) ) ;
}
// Make sure we always have at least 2 ticks
maxTicks = Math . max ( 2 , maxTicks ) ;
// To get a "nice" value for the tick spacing, we will use the appropriately named
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
// for details.
var spacing ;
var fixedStepSizeSet = ( this . options . ticks . fixedStepSize && this . options . ticks . fixedStepSize > 0 ) || ( this . options . ticks . stepSize && this . options . ticks . stepSize > 0 ) ;
if ( fixedStepSizeSet ) {
spacing = helpers . getValueOrDefault ( this . options . ticks . fixedStepSize , this . options . ticks . stepSize ) ;
} else {
var niceRange = helpers . niceNum ( this . max - this . min , false ) ;
spacing = helpers . niceNum ( niceRange / ( maxTicks - 1 ) , true ) ;
}
var niceMin = Math . floor ( this . min / spacing ) * spacing ;
var niceMax = Math . ceil ( this . max / spacing ) * spacing ;
var numSpaces = ( niceMax - niceMin ) / spacing ;
// If very close to our rounded value, use it.
if ( helpers . almostEquals ( numSpaces , Math . round ( numSpaces ) , spacing / 1000 ) ) {
numSpaces = Math . round ( numSpaces ) ;
} else {
numSpaces = Math . ceil ( numSpaces ) ;
}
// Put the values into the ticks array
this . ticks . push ( this . options . ticks . min !== undefined ? this . options . ticks . min : niceMin ) ;
for ( var j = 1 ; j < numSpaces ; ++ j ) {
this . ticks . push ( niceMin + ( j * spacing ) ) ;
}
this . ticks . push ( this . options . ticks . max !== undefined ? this . options . ticks . max : niceMax ) ;
if ( this . options . position === "left" || this . options . position === "right" ) {
// We are in a vertical orientation. The top value is the highest. So reverse the array
this . ticks . reverse ( ) ;
}
// At this point, we need to update our max and min given the tick values since we have expanded the
// range of the scale
this . max = helpers . max ( this . ticks ) ;
this . min = helpers . min ( this . ticks ) ;
if ( this . options . ticks . reverse ) {
this . ticks . reverse ( ) ;
this . start = this . max ;
this . end = this . min ;
} else {
this . start = this . min ;
this . end = this . max ;
}
} ,
getLabelForIndex : function ( index , datasetIndex ) {
return + this . getRightValue ( this . chart . data . datasets [ datasetIndex ] . data [ index ] ) ;
} ,
convertTicksToLabels : function ( ) {
this . ticksAsNumbers = this . ticks . slice ( ) ;
this . zeroLineIndex = this . ticks . indexOf ( 0 ) ;
Chart . Scale . prototype . convertTicksToLabels . call ( this ) ;
} ,
// Utils
getPixelForValue : function ( value , index , datasetIndex , includeOffset ) {
// This must be called after fit has been run so that
// this.left, this.top, this.right, and this.bottom have been defined
var rightValue = + this . getRightValue ( value ) ;
var pixel ;
var range = this . end - this . start ;
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
pixel = this . left + ( innerWidth / range * ( rightValue - this . start ) ) ;
return Math . round ( pixel + this . paddingLeft ) ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
pixel = ( this . bottom - this . paddingBottom ) - ( innerHeight / range * ( rightValue - this . start ) ) ;
return Math . round ( pixel ) ;
}
} ,
getValueForPixel : function ( pixel ) {
var offset ;
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
offset = ( pixel - this . left - this . paddingLeft ) / innerWidth ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
offset = ( this . bottom - this . paddingBottom - pixel ) / innerHeight ;
}
return this . start + ( ( this . end - this . start ) * offset ) ;
} ,
getPixelForTick : function ( index , includeOffset ) {
return this . getPixelForValue ( this . ticksAsNumbers [ index ] , null , null , includeOffset ) ;
}
} ) ;
Chart . scaleService . registerScaleType ( "linear" , LinearScale , defaultConfig ) ;
} ;
} , { } ] , 40 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var defaultConfig = {
position : "left" ,
// label settings
ticks : {
callback : function ( value , index , arr ) {
var remain = value / ( Math . pow ( 10 , Math . floor ( Chart . helpers . log10 ( value ) ) ) ) ;
if ( remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr . length - 1 ) {
return value . toExponential ( ) ;
} else {
return '' ;
}
}
}
} ;
var LogarithmicScale = Chart . Scale . extend ( {
determineDataLimits : function ( ) {
// Calculate Range
this . min = null ;
this . max = null ;
if ( this . options . stacked ) {
var valuesPerType = { } ;
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
var meta = this . chart . getDatasetMeta ( datasetIndex ) ;
if ( this . chart . isDatasetVisible ( datasetIndex ) && ( this . isHorizontal ( ) ? meta . xAxisID === this . id : meta . yAxisID === this . id ) ) {
if ( valuesPerType [ meta . type ] === undefined ) {
valuesPerType [ meta . type ] = [ ] ;
}
helpers . each ( dataset . data , function ( rawValue , index ) {
var values = valuesPerType [ meta . type ] ;
var value = + this . getRightValue ( rawValue ) ;
if ( isNaN ( value ) || meta . data [ index ] . hidden ) {
return ;
}
values [ index ] = values [ index ] || 0 ;
if ( this . options . relativePoints ) {
values [ index ] = 100 ;
} else {
// Don't need to split positive and negative since the log scale can't handle a 0 crossing
values [ index ] += value ;
}
} , this ) ;
}
} , this ) ;
helpers . each ( valuesPerType , function ( valuesForType ) {
var minVal = helpers . min ( valuesForType ) ;
var maxVal = helpers . max ( valuesForType ) ;
this . min = this . min === null ? minVal : Math . min ( this . min , minVal ) ;
this . max = this . max === null ? maxVal : Math . max ( this . max , maxVal ) ;
} , this ) ;
} else {
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
var meta = this . chart . getDatasetMeta ( datasetIndex ) ;
if ( this . chart . isDatasetVisible ( datasetIndex ) && ( this . isHorizontal ( ) ? meta . xAxisID === this . id : meta . yAxisID === this . id ) ) {
helpers . each ( dataset . data , function ( rawValue , index ) {
var value = + this . getRightValue ( rawValue ) ;
if ( isNaN ( value ) || meta . data [ index ] . hidden ) {
return ;
}
if ( this . min === null ) {
this . min = value ;
} else if ( value < this . min ) {
this . min = value ;
}
if ( this . max === null ) {
this . max = value ;
} else if ( value > this . max ) {
this . max = value ;
}
} , this ) ;
}
} , this ) ;
}
this . min = this . options . ticks . min !== undefined ? this . options . ticks . min : this . min ;
this . max = this . options . ticks . max !== undefined ? this . options . ticks . max : this . max ;
if ( this . min === this . max ) {
if ( this . min !== 0 && this . min !== null ) {
this . min = Math . pow ( 10 , Math . floor ( helpers . log10 ( this . min ) ) - 1 ) ;
this . max = Math . pow ( 10 , Math . floor ( helpers . log10 ( this . max ) ) + 1 ) ;
} else {
this . min = 1 ;
this . max = 10 ;
}
}
} ,
buildTicks : function ( ) {
// Reset the ticks array. Later on, we will draw a grid line at these positions
// The array simply contains the numerical value of the spots where ticks will be
this . ticks = [ ] ;
// Figure out what the max number of ticks we can support it is based on the size of
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
// the graph
var tickVal = this . options . ticks . min !== undefined ? this . options . ticks . min : Math . pow ( 10 , Math . floor ( helpers . log10 ( this . min ) ) ) ;
while ( tickVal < this . max ) {
this . ticks . push ( tickVal ) ;
var exp = Math . floor ( helpers . log10 ( tickVal ) ) ;
var significand = Math . floor ( tickVal / Math . pow ( 10 , exp ) ) + 1 ;
if ( significand === 10 ) {
significand = 1 ;
++ exp ;
}
tickVal = significand * Math . pow ( 10 , exp ) ;
}
var lastTick = this . options . ticks . max !== undefined ? this . options . ticks . max : tickVal ;
this . ticks . push ( lastTick ) ;
if ( this . options . position === "left" || this . options . position === "right" ) {
// We are in a vertical orientation. The top value is the highest. So reverse the array
this . ticks . reverse ( ) ;
}
// At this point, we need to update our max and min given the tick values since we have expanded the
// range of the scale
this . max = helpers . max ( this . ticks ) ;
this . min = helpers . min ( this . ticks ) ;
if ( this . options . ticks . reverse ) {
this . ticks . reverse ( ) ;
this . start = this . max ;
this . end = this . min ;
} else {
this . start = this . min ;
this . end = this . max ;
}
} ,
convertTicksToLabels : function ( ) {
this . tickValues = this . ticks . slice ( ) ;
Chart . Scale . prototype . convertTicksToLabels . call ( this ) ;
} ,
// Get the correct tooltip label
getLabelForIndex : function ( index , datasetIndex ) {
return + this . getRightValue ( this . chart . data . datasets [ datasetIndex ] . data [ index ] ) ;
} ,
getPixelForTick : function ( index , includeOffset ) {
return this . getPixelForValue ( this . tickValues [ index ] , null , null , includeOffset ) ;
} ,
getPixelForValue : function ( value , index , datasetIndex , includeOffset ) {
var pixel ;
var newVal = + this . getRightValue ( value )
; var range = helpers . log10 ( this . end ) - helpers . log10 ( this . start ) ;
if ( this . isHorizontal ( ) ) {
if ( newVal === 0 ) {
pixel = this . left + this . paddingLeft ;
} else {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
pixel = this . left + ( innerWidth / range * ( helpers . log10 ( newVal ) - helpers . log10 ( this . start ) ) ) ;
pixel += this . paddingLeft ;
}
} else {
// Bottom - top since pixels increase downard on a screen
if ( newVal === 0 ) {
pixel = this . top + this . paddingTop ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
pixel = ( this . bottom - this . paddingBottom ) - ( innerHeight / range * ( helpers . log10 ( newVal ) - helpers . log10 ( this . start ) ) ) ;
}
}
return pixel ;
} ,
getValueForPixel : function ( pixel ) {
var offset ;
var range = helpers . log10 ( this . end ) - helpers . log10 ( this . start ) ;
var value ;
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
value = this . start * Math . pow ( 10 , ( pixel - this . left - this . paddingLeft ) * range / innerWidth ) ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
value = Math . pow ( 10 , ( this . bottom - this . paddingBottom - pixel ) * range / innerHeight ) / this . start ;
}
return value ;
}
} ) ;
Chart . scaleService . registerScaleType ( "logarithmic" , LogarithmicScale , defaultConfig ) ;
} ;
} , { } ] , 41 : [ function ( require , module , exports ) {
"use strict" ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var defaultConfig = {
display : true ,
//Boolean - Whether to animate scaling the chart from the centre
animate : true ,
lineArc : false ,
position : "chartArea" ,
angleLines : {
display : true ,
color : "rgba(0, 0, 0, 0.1)" ,
lineWidth : 1
} ,
// label settings
ticks : {
//Boolean - Show a backdrop to the scale label
showLabelBackdrop : true ,
//String - The colour of the label backdrop
backdropColor : "rgba(255,255,255,0.75)" ,
//Number - The backdrop padding above & below the label in pixels
backdropPaddingY : 2 ,
//Number - The backdrop padding to the side of the label in pixels
backdropPaddingX : 2
} ,
pointLabels : {
//Number - Point label font size in pixels
fontSize : 10 ,
//Function - Used to convert point labels
callback : function ( label ) {
return label ;
}
}
} ;
var LinearRadialScale = Chart . Scale . extend ( {
getValueCount : function ( ) {
return this . chart . data . labels . length ;
} ,
setDimensions : function ( ) {
// Set the unconstrained dimension before label rotation
this . width = this . maxWidth ;
this . height = this . maxHeight ;
this . xCenter = Math . round ( this . width / 2 ) ;
this . yCenter = Math . round ( this . height / 2 ) ;
var minSize = helpers . min ( [ this . height , this . width ] ) ;
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
this . drawingArea = ( this . options . display ) ? ( minSize / 2 ) - ( tickFontSize / 2 + this . options . ticks . backdropPaddingY ) : ( minSize / 2 ) ;
} ,
determineDataLimits : function ( ) {
this . min = null ;
this . max = null ;
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
if ( this . chart . isDatasetVisible ( datasetIndex ) ) {
var meta = this . chart . getDatasetMeta ( datasetIndex ) ;
helpers . each ( dataset . data , function ( rawValue , index ) {
var value = + this . getRightValue ( rawValue ) ;
if ( isNaN ( value ) || meta . data [ index ] . hidden ) {
return ;
}
if ( this . min === null ) {
this . min = value ;
} else if ( value < this . min ) {
this . min = value ;
}
if ( this . max === null ) {
this . max = value ;
} else if ( value > this . max ) {
this . max = value ;
}
} , this ) ;
}
} , this ) ;
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
// do nothing since that would make the chart weird. If the user really wants a weird chart
// axis, they can manually override it
if ( this . options . ticks . beginAtZero ) {
var minSign = helpers . sign ( this . min ) ;
var maxSign = helpers . sign ( this . max ) ;
if ( minSign < 0 && maxSign < 0 ) {
// move the top up to 0
this . max = 0 ;
} else if ( minSign > 0 && maxSign > 0 ) {
// move the botttom down to 0
this . min = 0 ;
}
}
if ( this . options . ticks . min !== undefined ) {
this . min = this . options . ticks . min ;
} else if ( this . options . ticks . suggestedMin !== undefined ) {
this . min = Math . min ( this . min , this . options . ticks . suggestedMin ) ;
}
if ( this . options . ticks . max !== undefined ) {
this . max = this . options . ticks . max ;
} else if ( this . options . ticks . suggestedMax !== undefined ) {
this . max = Math . max ( this . max , this . options . ticks . suggestedMax ) ;
}
if ( this . min === this . max ) {
this . min -- ;
this . max ++ ;
}
} ,
buildTicks : function ( ) {
this . ticks = [ ] ;
// Figure out what the max number of ticks we can support it is based on the size of
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
// the graph
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
var maxTicks = Math . min ( this . options . ticks . maxTicksLimit ? this . options . ticks . maxTicksLimit : 11 , Math . ceil ( this . drawingArea / ( 1.5 * tickFontSize ) ) ) ;
maxTicks = Math . max ( 2 , maxTicks ) ; // Make sure we always have at least 2 ticks
// To get a "nice" value for the tick spacing, we will use the appropriately named
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
// for details.
var niceRange = helpers . niceNum ( this . max - this . min , false ) ;
var spacing = helpers . niceNum ( niceRange / ( maxTicks - 1 ) , true ) ;
var niceMin = Math . floor ( this . min / spacing ) * spacing ;
var niceMax = Math . ceil ( this . max / spacing ) * spacing ;
var numSpaces = Math . ceil ( ( niceMax - niceMin ) / spacing ) ;
// Put the values into the ticks array
this . ticks . push ( this . options . ticks . min !== undefined ? this . options . ticks . min : niceMin ) ;
for ( var j = 1 ; j < numSpaces ; ++ j ) {
this . ticks . push ( niceMin + ( j * spacing ) ) ;
}
this . ticks . push ( this . options . ticks . max !== undefined ? this . options . ticks . max : niceMax ) ;
// At this point, we need to update our max and min given the tick values since we have expanded the
// range of the scale
this . max = helpers . max ( this . ticks ) ;
this . min = helpers . min ( this . ticks ) ;
if ( this . options . ticks . reverse ) {
this . ticks . reverse ( ) ;
this . start = this . max ;
this . end = this . min ;
} else {
this . start = this . min ;
this . end = this . max ;
}
this . zeroLineIndex = this . ticks . indexOf ( 0 ) ;
} ,
convertTicksToLabels : function ( ) {
Chart . Scale . prototype . convertTicksToLabels . call ( this ) ;
// Point labels
this . pointLabels = this . chart . data . labels . map ( this . options . pointLabels . callback , this ) ;
} ,
getLabelForIndex : function ( index , datasetIndex ) {
return + this . getRightValue ( this . chart . data . datasets [ datasetIndex ] . data [ index ] ) ;
} ,
fit : function ( ) {
/ *
* Right , this is really confusing and there is a lot of maths going on here
* The gist of the problem is here : https : //gist.github.com/nnnick/696cc9c55f4b0beb8fe9
*
* Reaction : https : //dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
*
* Solution :
*
* We assume the radius of the polygon is half the size of the canvas at first
* at each index we check if the text overlaps .
*
* Where it does , we store that angle and that index .
*
* After finding the largest index and angle we calculate how much we need to remove
* from the shape radius to move the point inwards by that x .
*
* We average the left and right distances to get the maximum shape radius that can fit in the box
* along with labels .
*
* Once we have that , we can find the centre point for the chart , by taking the x text protrusion
* on each side , removing that from the size , halving it and adding the left x protrusion width .
*
* This will mean we have a shape fitted to the canvas , as large as it can be with the labels
* and position it in the most space efficient manner
*
* https : //dl.dropboxusercontent.com/u/34601363/yeahscience.gif
* /
var pointLabelFontSize = helpers . getValueOrDefault ( this . options . pointLabels . fontSize , Chart . defaults . global . defaultFontSize ) ;
var pointLabeFontStyle = helpers . getValueOrDefault ( this . options . pointLabels . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var pointLabeFontFamily = helpers . getValueOrDefault ( this . options . pointLabels . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var pointLabeFont = helpers . fontString ( pointLabelFontSize , pointLabeFontStyle , pointLabeFontFamily ) ;
// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
var largestPossibleRadius = helpers . min ( [ ( this . height / 2 - pointLabelFontSize - 5 ) , this . width / 2 ] ) ,
pointPosition ,
i ,
textWidth ,
halfTextWidth ,
furthestRight = this . width ,
furthestRightIndex ,
furthestRightAngle ,
furthestLeft = 0 ,
furthestLeftIndex ,
furthestLeftAngle ,
xProtrusionLeft ,
xProtrusionRight ,
radiusReductionRight ,
radiusReductionLeft ,
maxWidthRadius ;
this . ctx . font = pointLabeFont ;
for ( i = 0 ; i < this . getValueCount ( ) ; i ++ ) {
// 5px to space the text slightly out - similar to what we do in the draw function.
pointPosition = this . getPointPosition ( i , largestPossibleRadius ) ;
textWidth = this . ctx . measureText ( this . pointLabels [ i ] ? this . pointLabels [ i ] : '' ) . width + 5 ;
if ( i === 0 || i === this . getValueCount ( ) / 2 ) {
// If we're at index zero, or exactly the middle, we're at exactly the top/bottom
// of the radar chart, so text will be aligned centrally, so we'll half it and compare
// w/left and right text sizes
halfTextWidth = textWidth / 2 ;
if ( pointPosition . x + halfTextWidth > furthestRight ) {
furthestRight = pointPosition . x + halfTextWidth ;
furthestRightIndex = i ;
}
if ( pointPosition . x - halfTextWidth < furthestLeft ) {
furthestLeft = pointPosition . x - halfTextWidth ;
furthestLeftIndex = i ;
}
} else if ( i < this . getValueCount ( ) / 2 ) {
// Less than half the values means we'll left align the text
if ( pointPosition . x + textWidth > furthestRight ) {
furthestRight = pointPosition . x + textWidth ;
furthestRightIndex = i ;
}
} else if ( i > this . getValueCount ( ) / 2 ) {
// More than half the values means we'll right align the text
if ( pointPosition . x - textWidth < furthestLeft ) {
furthestLeft = pointPosition . x - textWidth ;
furthestLeftIndex = i ;
}
}
}
xProtrusionLeft = furthestLeft ;
xProtrusionRight = Math . ceil ( furthestRight - this . width ) ;
furthestRightAngle = this . getIndexAngle ( furthestRightIndex ) ;
furthestLeftAngle = this . getIndexAngle ( furthestLeftIndex ) ;
radiusReductionRight = xProtrusionRight / Math . sin ( furthestRightAngle + Math . PI / 2 ) ;
radiusReductionLeft = xProtrusionLeft / Math . sin ( furthestLeftAngle + Math . PI / 2 ) ;
// Ensure we actually need to reduce the size of the chart
radiusReductionRight = ( helpers . isNumber ( radiusReductionRight ) ) ? radiusReductionRight : 0 ;
radiusReductionLeft = ( helpers . isNumber ( radiusReductionLeft ) ) ? radiusReductionLeft : 0 ;
this . drawingArea = Math . round ( largestPossibleRadius - ( radiusReductionLeft + radiusReductionRight ) / 2 ) ;
this . setCenterPoint ( radiusReductionLeft , radiusReductionRight ) ;
} ,
setCenterPoint : function ( leftMovement , rightMovement ) {
var maxRight = this . width - rightMovement - this . drawingArea ,
maxLeft = leftMovement + this . drawingArea ;
this . xCenter = Math . round ( ( ( maxLeft + maxRight ) / 2 ) + this . left ) ;
// Always vertically in the centre as the text height doesn't change
this . yCenter = Math . round ( ( this . height / 2 ) + this . top ) ;
} ,
getIndexAngle : function ( index ) {
var angleMultiplier = ( Math . PI * 2 ) / this . getValueCount ( ) ;
// Start from the top instead of right, so remove a quarter of the circle
return index * angleMultiplier - ( Math . PI / 2 ) ;
} ,
getDistanceFromCenterForValue : function ( value ) {
if ( value === null ) {
return 0 ; // null always in center
}
// Take into account half font size + the yPadding of the top value
var scalingFactor = this . drawingArea / ( this . max - this . min ) ;
if ( this . options . reverse ) {
return ( this . max - value ) * scalingFactor ;
} else {
return ( value - this . min ) * scalingFactor ;
}
} ,
getPointPosition : function ( index , distanceFromCenter ) {
var thisAngle = this . getIndexAngle ( index ) ;
return {
x : Math . round ( Math . cos ( thisAngle ) * distanceFromCenter ) + this . xCenter ,
y : Math . round ( Math . sin ( thisAngle ) * distanceFromCenter ) + this . yCenter
} ;
} ,
getPointPositionForValue : function ( index , value ) {
return this . getPointPosition ( index , this . getDistanceFromCenterForValue ( value ) ) ;
} ,
draw : function ( ) {
if ( this . options . display ) {
var ctx = this . ctx ;
helpers . each ( this . ticks , function ( label , index ) {
// Don't draw a centre value (if it is minimum)
if ( index > 0 || this . options . reverse ) {
var yCenterOffset = this . getDistanceFromCenterForValue ( this . ticks [ index ] ) ;
var yHeight = this . yCenter - yCenterOffset ;
// Draw circular lines around the scale
if ( this . options . gridLines . display ) {
ctx . strokeStyle = this . options . gridLines . color ;
ctx . lineWidth = this . options . gridLines . lineWidth ;
if ( this . options . lineArc ) {
// Draw circular arcs between the points
ctx . beginPath ( ) ;
ctx . arc ( this . xCenter , this . yCenter , yCenterOffset , 0 , Math . PI * 2 ) ;
ctx . closePath ( ) ;
ctx . stroke ( ) ;
} else {
// Draw straight lines connecting each index
ctx . beginPath ( ) ;
for ( var i = 0 ; i < this . getValueCount ( ) ; i ++ ) {
var pointPosition = this . getPointPosition ( i , this . getDistanceFromCenterForValue ( this . ticks [ index ] ) ) ;
if ( i === 0 ) {
ctx . moveTo ( pointPosition . x , pointPosition . y ) ;
} else {
ctx . lineTo ( pointPosition . x , pointPosition . y ) ;
}
}
ctx . closePath ( ) ;
ctx . stroke ( ) ;
}
}
if ( this . options . ticks . display ) {
var tickFontColor = helpers . getValueOrDefault ( this . options . ticks . fontColor , Chart . defaults . global . defaultFontColor ) ;
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
var tickFontStyle = helpers . getValueOrDefault ( this . options . ticks . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var tickFontFamily = helpers . getValueOrDefault ( this . options . ticks . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var tickLabelFont = helpers . fontString ( tickFontSize , tickFontStyle , tickFontFamily ) ;
ctx . font = tickLabelFont ;
if ( this . options . ticks . showLabelBackdrop ) {
var labelWidth = ctx . measureText ( label ) . width ;
ctx . fillStyle = this . options . ticks . backdropColor ;
ctx . fillRect (
this . xCenter - labelWidth / 2 - this . options . ticks . backdropPaddingX ,
yHeight - tickFontSize / 2 - this . options . ticks . backdropPaddingY ,
labelWidth + this . options . ticks . backdropPaddingX * 2 ,
tickFontSize + this . options . ticks . backdropPaddingY * 2
) ;
}
ctx . textAlign = 'center' ;
ctx . textBaseline = "middle" ;
ctx . fillStyle = tickFontColor ;
ctx . fillText ( label , this . xCenter , yHeight ) ;
}
}
} , this ) ;
if ( ! this . options . lineArc ) {
ctx . lineWidth = this . options . angleLines . lineWidth ;
ctx . strokeStyle = this . options . angleLines . color ;
for ( var i = this . getValueCount ( ) - 1 ; i >= 0 ; i -- ) {
if ( this . options . angleLines . display ) {
var outerPosition = this . getPointPosition ( i , this . getDistanceFromCenterForValue ( this . options . reverse ? this . min : this . max ) ) ;
ctx . beginPath ( ) ;
ctx . moveTo ( this . xCenter , this . yCenter ) ;
ctx . lineTo ( outerPosition . x , outerPosition . y ) ;
ctx . stroke ( ) ;
ctx . closePath ( ) ;
}
// Extra 3px out for some label spacing
var pointLabelPosition = this . getPointPosition ( i , this . getDistanceFromCenterForValue ( this . options . reverse ? this . min : this . max ) + 5 ) ;
var pointLabelFontColor = helpers . getValueOrDefault ( this . options . pointLabels . fontColor , Chart . defaults . global . defaultFontColor ) ;
var pointLabelFontSize = helpers . getValueOrDefault ( this . options . pointLabels . fontSize , Chart . defaults . global . defaultFontSize ) ;
var pointLabeFontStyle = helpers . getValueOrDefault ( this . options . pointLabels . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var pointLabeFontFamily = helpers . getValueOrDefault ( this . options . pointLabels . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var pointLabeFont = helpers . fontString ( pointLabelFontSize , pointLabeFontStyle , pointLabeFontFamily ) ;
ctx . font = pointLabeFont ;
ctx . fillStyle = pointLabelFontColor ;
var labelsCount = this . pointLabels . length ,
halfLabelsCount = this . pointLabels . length / 2 ,
quarterLabelsCount = halfLabelsCount / 2 ,
upperHalf = ( i < quarterLabelsCount || i > labelsCount - quarterLabelsCount ) ,
exactQuarter = ( i === quarterLabelsCount || i === labelsCount - quarterLabelsCount ) ;
if ( i === 0 ) {
ctx . textAlign = 'center' ;
} else if ( i === halfLabelsCount ) {
ctx . textAlign = 'center' ;
} else if ( i < halfLabelsCount ) {
ctx . textAlign = 'left' ;
} else {
ctx . textAlign = 'right' ;
}
// Set the correct text baseline based on outer positioning
if ( exactQuarter ) {
ctx . textBaseline = 'middle' ;
} else if ( upperHalf ) {
ctx . textBaseline = 'bottom' ;
} else {
ctx . textBaseline = 'top' ;
}
ctx . fillText ( this . pointLabels [ i ] ? this . pointLabels [ i ] : '' , pointLabelPosition . x , pointLabelPosition . y ) ;
}
}
}
}
} ) ;
Chart . scaleService . registerScaleType ( "radialLinear" , LinearRadialScale , defaultConfig ) ;
} ;
} , { } ] , 42 : [ function ( require , module , exports ) {
/*global window: false */
"use strict" ;
var moment = require ( 'moment' ) ;
moment = typeof ( moment ) === 'function' ? moment : window . moment ;
module . exports = function ( Chart ) {
var helpers = Chart . helpers ;
var time = {
units : [ {
name : 'millisecond' ,
steps : [ 1 , 2 , 5 , 10 , 20 , 50 , 100 , 250 , 500 ]
} , {
name : 'second' ,
steps : [ 1 , 2 , 5 , 10 , 30 ]
} , {
name : 'minute' ,
steps : [ 1 , 2 , 5 , 10 , 30 ]
} , {
name : 'hour' ,
steps : [ 1 , 2 , 3 , 6 , 12 ]
} , {
name : 'day' ,
steps : [ 1 , 2 , 5 ]
} , {
name : 'week' ,
maxStep : 4
} , {
name : 'month' ,
maxStep : 3
} , {
name : 'quarter' ,
maxStep : 4
} , {
name : 'year' ,
maxStep : false
} ]
} ;
var defaultConfig = {
position : "bottom" ,
time : {
parser : false , // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
format : false , // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
unit : false , // false == automatic or override with week, month, year, etc.
round : false , // none, or override with week, month, year, etc.
displayFormat : false , // DEPRECATED
isoWeekday : false , // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
displayFormats : {
'millisecond' : 'h:mm:ss.SSS a' , // 11:20:01.123 AM,
'second' : 'h:mm:ss a' , // 11:20:01 AM
'minute' : 'h:mm:ss a' , // 11:20:01 AM
'hour' : 'MMM D, hA' , // Sept 4, 5PM
'day' : 'll' , // Sep 4 2015
'week' : 'll' , // Week 46, or maybe "[W]WW - YYYY" ?
'month' : 'MMM YYYY' , // Sept 2015
'quarter' : '[Q]Q - YYYY' , // Q3
'year' : 'YYYY' // 2015
}
} ,
ticks : {
autoSkip : false
}
} ;
var TimeScale = Chart . Scale . extend ( {
initialize : function ( ) {
if ( ! moment ) {
throw new Error ( 'Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com' ) ;
}
Chart . Scale . prototype . initialize . call ( this ) ;
} ,
getLabelMoment : function ( datasetIndex , index ) {
return this . labelMoments [ datasetIndex ] [ index ] ;
} ,
getMomentStartOf : function ( tick ) {
if ( this . options . time . unit === 'week' && this . options . time . isoWeekday !== false ) {
return tick . clone ( ) . startOf ( 'isoWeek' ) . isoWeekday ( this . options . time . isoWeekday ) ;
} else {
return tick . clone ( ) . startOf ( this . tickUnit ) ;
}
} ,
determineDataLimits : function ( ) {
this . labelMoments = [ ] ;
// Only parse these once. If the dataset does not have data as x,y pairs, we will use
// these
var scaleLabelMoments = [ ] ;
if ( this . chart . data . labels && this . chart . data . labels . length > 0 ) {
helpers . each ( this . chart . data . labels , function ( label , index ) {
var labelMoment = this . parseTime ( label ) ;
if ( labelMoment . isValid ( ) ) {
if ( this . options . time . round ) {
labelMoment . startOf ( this . options . time . round ) ;
}
scaleLabelMoments . push ( labelMoment ) ;
}
} , this ) ;
this . firstTick = moment . min . call ( this , scaleLabelMoments ) ;
this . lastTick = moment . max . call ( this , scaleLabelMoments ) ;
} else {
this . firstTick = null ;
this . lastTick = null ;
}
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
var momentsForDataset = [ ] ;
var datasetVisible = this . chart . isDatasetVisible ( datasetIndex ) ;
if ( typeof dataset . data [ 0 ] === 'object' ) {
helpers . each ( dataset . data , function ( value , index ) {
var labelMoment = this . parseTime ( this . getRightValue ( value ) ) ;
if ( labelMoment . isValid ( ) ) {
if ( this . options . time . round ) {
labelMoment . startOf ( this . options . time . round ) ;
}
momentsForDataset . push ( labelMoment ) ;
if ( datasetVisible ) {
// May have gone outside the scale ranges, make sure we keep the first and last ticks updated
this . firstTick = this . firstTick !== null ? moment . min ( this . firstTick , labelMoment ) : labelMoment ;
this . lastTick = this . lastTick !== null ? moment . max ( this . lastTick , labelMoment ) : labelMoment ;
}
}
} , this ) ;
} else {
// We have no labels. Use the ones from the scale
momentsForDataset = scaleLabelMoments ;
}
this . labelMoments . push ( momentsForDataset ) ;
} , this ) ;
// Set these after we've done all the data
if ( this . options . time . min ) {
this . firstTick = this . parseTime ( this . options . time . min ) ;
}
if ( this . options . time . max ) {
this . lastTick = this . parseTime ( this . options . time . max ) ;
}
// We will modify these, so clone for later
this . firstTick = ( this . firstTick || moment ( ) ) . clone ( ) ;
this . lastTick = ( this . lastTick || moment ( ) ) . clone ( ) ;
} ,
buildTicks : function ( index ) {
this . ctx . save ( ) ;
var tickFontSize = helpers . getValueOrDefault ( this . options . ticks . fontSize , Chart . defaults . global . defaultFontSize ) ;
var tickFontStyle = helpers . getValueOrDefault ( this . options . ticks . fontStyle , Chart . defaults . global . defaultFontStyle ) ;
var tickFontFamily = helpers . getValueOrDefault ( this . options . ticks . fontFamily , Chart . defaults . global . defaultFontFamily ) ;
var tickLabelFont = helpers . fontString ( tickFontSize , tickFontStyle , tickFontFamily ) ;
this . ctx . font = tickLabelFont ;
this . ticks = [ ] ;
this . unitScale = 1 ; // How much we scale the unit by, ie 2 means 2x unit per step
this . scaleSizeInUnits = 0 ; // How large the scale is in the base unit (seconds, minutes, etc)
// Set unit override if applicable
if ( this . options . time . unit ) {
this . tickUnit = this . options . time . unit || 'day' ;
this . displayFormat = this . options . time . displayFormats [ this . tickUnit ] ;
this . scaleSizeInUnits = this . lastTick . diff ( this . firstTick , this . tickUnit , true ) ;
this . unitScale = helpers . getValueOrDefault ( this . options . time . unitStepSize , 1 ) ;
} else {
// Determine the smallest needed unit of the time
var innerWidth = this . isHorizontal ( ) ? this . width - ( this . paddingLeft + this . paddingRight ) : this . height - ( this . paddingTop + this . paddingBottom ) ;
// Crude approximation of what the label length might be
var tempFirstLabel = this . tickFormatFunction ( this . firstTick , 0 , [ ] ) ;
var tickLabelWidth = this . ctx . measureText ( tempFirstLabel ) . width ;
var cosRotation = Math . cos ( helpers . toRadians ( this . options . ticks . maxRotation ) ) ;
var sinRotation = Math . sin ( helpers . toRadians ( this . options . ticks . maxRotation ) ) ;
tickLabelWidth = ( tickLabelWidth * cosRotation ) + ( tickFontSize * sinRotation ) ;
var labelCapacity = innerWidth / ( tickLabelWidth ) ;
// Start as small as possible
this . tickUnit = 'millisecond' ;
this . scaleSizeInUnits = this . lastTick . diff ( this . firstTick , this . tickUnit , true ) ;
this . displayFormat = this . options . time . displayFormats [ this . tickUnit ] ;
var unitDefinitionIndex = 0 ;
var unitDefinition = time . units [ unitDefinitionIndex ] ;
// While we aren't ideal and we don't have units left
while ( unitDefinitionIndex < time . units . length ) {
// Can we scale this unit. If `false` we can scale infinitely
this . unitScale = 1 ;
if ( helpers . isArray ( unitDefinition . steps ) && Math . ceil ( this . scaleSizeInUnits / labelCapacity ) < helpers . max ( unitDefinition . steps ) ) {
// Use one of the prefedined steps
for ( var idx = 0 ; idx < unitDefinition . steps . length ; ++ idx ) {
if ( unitDefinition . steps [ idx ] >= Math . ceil ( this . scaleSizeInUnits / labelCapacity ) ) {
this . unitScale = helpers . getValueOrDefault ( this . options . time . unitStepSize , unitDefinition . steps [ idx ] ) ;
break ;
}
}
break ;
} else if ( ( unitDefinition . maxStep === false ) || ( Math . ceil ( this . scaleSizeInUnits / labelCapacity ) < unitDefinition . maxStep ) ) {
// We have a max step. Scale this unit
this . unitScale = helpers . getValueOrDefault ( this . options . time . unitStepSize , Math . ceil ( this . scaleSizeInUnits / labelCapacity ) ) ;
break ;
} else {
// Move to the next unit up
++ unitDefinitionIndex ;
unitDefinition = time . units [ unitDefinitionIndex ] ;
this . tickUnit = unitDefinition . name ;
var leadingUnitBuffer = this . firstTick . diff ( this . getMomentStartOf ( this . firstTick ) , this . tickUnit , true ) ;
var trailingUnitBuffer = this . getMomentStartOf ( this . lastTick . clone ( ) . add ( 1 , this . tickUnit ) ) . diff ( this . lastTick , this . tickUnit , true ) ;
this . scaleSizeInUnits = this . lastTick . diff ( this . firstTick , this . tickUnit , true ) + leadingUnitBuffer + trailingUnitBuffer ;
this . displayFormat = this . options . time . displayFormats [ unitDefinition . name ] ;
}
}
}
var roundedStart ;
// Only round the first tick if we have no hard minimum
if ( ! this . options . time . min ) {
this . firstTick = this . getMomentStartOf ( this . firstTick ) ;
roundedStart = this . firstTick ;
} else {
roundedStart = this . getMomentStartOf ( this . firstTick ) ;
}
// Only round the last tick if we have no hard maximum
if ( ! this . options . time . max ) {
var roundedEnd = this . getMomentStartOf ( this . lastTick ) ;
if ( roundedEnd . diff ( this . lastTick , this . tickUnit , true ) !== 0 ) {
// Do not use end of because we need this to be in the next time unit
this . lastTick = this . getMomentStartOf ( this . lastTick . add ( 1 , this . tickUnit ) ) ;
}
}
this . smallestLabelSeparation = this . width ;
helpers . each ( this . chart . data . datasets , function ( dataset , datasetIndex ) {
for ( var i = 1 ; i < this . labelMoments [ datasetIndex ] . length ; i ++ ) {
this . smallestLabelSeparation = Math . min ( this . smallestLabelSeparation , this . labelMoments [ datasetIndex ] [ i ] . diff ( this . labelMoments [ datasetIndex ] [ i - 1 ] , this . tickUnit , true ) ) ;
}
} , this ) ;
// Tick displayFormat override
if ( this . options . time . displayFormat ) {
this . displayFormat = this . options . time . displayFormat ;
}
// first tick. will have been rounded correctly if options.time.min is not specified
this . ticks . push ( this . firstTick . clone ( ) ) ;
// For every unit in between the first and last moment, create a moment and add it to the ticks tick
for ( var i = 1 ; i <= this . scaleSizeInUnits ; ++ i ) {
var newTick = roundedStart . clone ( ) . add ( i , this . tickUnit ) ;
// Are we greater than the max time
if ( this . options . time . max && newTick . diff ( this . lastTick , this . tickUnit , true ) >= 0 ) {
break ;
}
if ( i % this . unitScale === 0 ) {
this . ticks . push ( newTick ) ;
}
}
// Always show the right tick
var diff = this . ticks [ this . ticks . length - 1 ] . diff ( this . lastTick , this . tickUnit ) ;
if ( diff !== 0 || this . scaleSizeInUnits === 0 ) {
// this is a weird case. If the <max> option is the same as the end option, we can't just diff the times because the tick was created from the roundedStart
// but the last tick was not rounded.
if ( this . options . time . max ) {
this . ticks . push ( this . lastTick . clone ( ) ) ;
this . scaleSizeInUnits = this . lastTick . diff ( this . ticks [ 0 ] , this . tickUnit , true ) ;
} else {
this . ticks . push ( this . lastTick . clone ( ) ) ;
this . scaleSizeInUnits = this . lastTick . diff ( this . firstTick , this . tickUnit , true ) ;
}
}
this . ctx . restore ( ) ;
} ,
// Get tooltip label
getLabelForIndex : function ( index , datasetIndex ) {
var label = this . chart . data . labels && index < this . chart . data . labels . length ? this . chart . data . labels [ index ] : '' ;
if ( typeof this . chart . data . datasets [ datasetIndex ] . data [ 0 ] === 'object' ) {
label = this . getRightValue ( this . chart . data . datasets [ datasetIndex ] . data [ index ] ) ;
}
// Format nicely
if ( this . options . time . tooltipFormat ) {
label = this . parseTime ( label ) . format ( this . options . time . tooltipFormat ) ;
}
return label ;
} ,
// Function to format an individual tick mark
tickFormatFunction : function tickFormatFunction ( tick , index , ticks ) {
var formattedTick = tick . format ( this . displayFormat ) ;
var tickOpts = this . options . ticks ;
var callback = helpers . getValueOrDefault ( tickOpts . callback , tickOpts . userCallback ) ;
if ( callback ) {
return callback ( formattedTick , index , ticks ) ;
} else {
return formattedTick ;
}
} ,
convertTicksToLabels : function ( ) {
this . tickMoments = this . ticks ;
this . ticks = this . ticks . map ( this . tickFormatFunction , this ) ;
} ,
getPixelForValue : function ( value , index , datasetIndex , includeOffset ) {
var labelMoment = value && value . isValid && value . isValid ( ) ? value : this . getLabelMoment ( datasetIndex , index ) ;
if ( labelMoment ) {
var offset = labelMoment . diff ( this . firstTick , this . tickUnit , true ) ;
var decimal = offset / this . scaleSizeInUnits ;
if ( this . isHorizontal ( ) ) {
var innerWidth = this . width - ( this . paddingLeft + this . paddingRight ) ;
var valueWidth = innerWidth / Math . max ( this . ticks . length - 1 , 1 ) ;
var valueOffset = ( innerWidth * decimal ) + this . paddingLeft ;
return this . left + Math . round ( valueOffset ) ;
} else {
var innerHeight = this . height - ( this . paddingTop + this . paddingBottom ) ;
var valueHeight = innerHeight / Math . max ( this . ticks . length - 1 , 1 ) ;
var heightOffset = ( innerHeight * decimal ) + this . paddingTop ;
return this . top + Math . round ( heightOffset ) ;
}
}
} ,
getPixelForTick : function ( index , includeOffset ) {
return this . getPixelForValue ( this . tickMoments [ index ] , null , null , includeOffset ) ;
} ,
getValueForPixel : function ( pixel ) {
var innerDimension = this . isHorizontal ( ) ? this . width - ( this . paddingLeft + this . paddingRight ) : this . height - ( this . paddingTop + this . paddingBottom ) ;
var offset = ( pixel - ( this . isHorizontal ( ) ? this . left + this . paddingLeft : this . top + this . paddingTop ) ) / innerDimension ;
offset *= this . scaleSizeInUnits ;
return this . firstTick . clone ( ) . add ( moment . duration ( offset , this . tickUnit ) . asSeconds ( ) , 'seconds' ) ;
} ,
parseTime : function ( label ) {
if ( typeof this . options . time . parser === 'string' ) {
return moment ( label , this . options . time . parser ) ;
}
if ( typeof this . options . time . parser === 'function' ) {
return this . options . time . parser ( label ) ;
}
// Date objects
if ( typeof label . getMonth === 'function' || typeof label === 'number' ) {
return moment ( label ) ;
}
// Moment support
if ( label . isValid && label . isValid ( ) ) {
return label ;
}
// Custom parsing (return an instance of moment)
if ( typeof this . options . time . format !== 'string' && this . options . time . format . call ) {
console . warn ( "options.time.format is deprecated and replaced by options.time.parser. See http://nnnick.github.io/Chart.js/docs-v2/#scales-time-scale" ) ;
return this . options . time . format ( label ) ;
}
// Moment format parsing
return moment ( label , this . options . time . format ) ;
}
} ) ;
Chart . scaleService . registerScaleType ( "time" , TimeScale , defaultConfig ) ;
} ;
} , { "moment" : 6 } ] } , { } , [ 7 ] ) ;