@@ -14,23 +14,49 @@ var isNumeric = require('fast-isnumeric');
1414var  Lib  =  require ( '../../lib' ) ; 
1515var  BADNUM  =  require ( '../../constants/numerical' ) . BADNUM ; 
1616
17+ var  isArrayOrTypedArray  =  Lib . isArrayOrTypedArray ; 
18+ var  isDateTime  =  Lib . isDateTime ; 
19+ var  cleanNumber  =  Lib . cleanNumber ; 
20+ var  round  =  Math . round ; 
21+ 
1722module . exports  =  function  autoType ( array ,  calendar ,  opts )  { 
18-     opts  =  opts  ||  { } ; 
23+     var  a  =  array ; 
24+ 
25+     var  noMultiCategory  =  opts . noMultiCategory ; 
26+     if ( isArrayOrTypedArray ( a )  &&  ! a . length )  return  '-' ; 
27+     if ( ! noMultiCategory  &&  multiCategory ( a ) )  return  'multicategory' ; 
28+     if ( noMultiCategory  &&  Array . isArray ( a [ 0 ] ) )  {  // no need to flat typed arrays here 
29+         var  b  =  [ ] ; 
30+         for ( var  i  =  0 ;  i  <  a . length ;  i ++ )  { 
31+             if ( isArrayOrTypedArray ( a [ i ] ) )  { 
32+                 for ( var  j  =  0 ;  j  <  a [ i ] . length ;  j ++ )  { 
33+                     b . push ( a [ i ] [ j ] ) ; 
34+                 } 
35+             } 
36+         } 
37+         a  =  b ; 
38+     } 
39+ 
40+     if ( moreDates ( a ,  calendar ) )  return  'date' ; 
1941
20-     if ( ! opts . noMultiCategory   &&   multiCategory ( array ) )   return   'multicategory' ; 
21-     if ( moreDates ( array ,   calendar ) )  return  'date ' ; 
22-     if ( category ( array ) )  return  'category ' ; 
23-      if ( linearOK ( array ) )   return   'linear' ; 
24-     else   return  '-' ; 
42+     var   convertNumeric   =   opts . autotypenumbers   !==   'strict' ;   // compare against strict, just in case autotypenumbers was not provided in opts 
43+     if ( category ( a ,   convertNumeric ) )  return  'category ' ; 
44+     if ( linearOK ( a ,   convertNumeric ) )  return  'linear ' ; 
45+ 
46+     return  '-' ; 
2547} ; 
2648
49+ function  hasTypeNumber ( v ,  convertNumeric )  { 
50+     return  convertNumeric  ? isNumeric ( v )  : typeof  v  ===  'number' ; 
51+ } 
52+ 
2753// is there at least one number in array? If not, we should leave 
2854// ax.type empty so it can be autoset later 
29- function  linearOK ( array )  { 
30-     if ( ! array )   return   false ; 
55+ function  linearOK ( a ,   convertNumeric )  { 
56+     var   len   =   a . length ; 
3157
32-     for ( var  i  =  0 ;  i  <  array . length ;  i ++ )  { 
33-         if ( isNumeric ( array [ i ] ) )  return  true ; 
58+     for ( var  i  =  0 ;  i  <  len ;  i ++ )  { 
59+         if ( hasTypeNumber ( a [ i ] ,   convertNumeric ) )  return  true ; 
3460    } 
3561
3662    return  false ; 
@@ -43,51 +69,61 @@ function linearOK(array) {
4369// numbers and a few dates 
4470// as with categories, consider DISTINCT values only. 
4571function  moreDates ( a ,  calendar )  { 
46-     // test at most 1000 points, evenly spaced 
47-     var  inc  =  Math . max ( 1 ,  ( a . length  -  1 )  /  1000 ) ; 
48-     var  dcnt  =  0 ; 
49-     var  ncnt  =  0 ; 
72+     var  len  =  a . length ; 
73+ 
74+     var  inc  =  getIncrement ( len ) ; 
75+     var  dats  =  0 ; 
76+     var  nums  =  0 ; 
5077    var  seen  =  { } ; 
5178
52-     for ( var  i  =  0 ;  i  <  a . length ;  i  +=  inc )  { 
53-         var  ai  =  a [ Math . round ( i ) ] ; 
79+     for ( var  f  =  0 ;  f  <  len ;  f  +=  inc )  { 
80+         var  i  =  round ( f ) ; 
81+         var  ai  =  a [ i ] ; 
5482        var  stri  =  String ( ai ) ; 
5583        if ( seen [ stri ] )  continue ; 
5684        seen [ stri ]  =  1 ; 
5785
58-         if ( Lib . isDateTime ( ai ,  calendar ) )  dcnt   +=   1 ; 
59-         if ( isNumeric ( ai ) )  ncnt   +=   1 ; 
86+         if ( isDateTime ( ai ,  calendar ) )  dats ++ ; 
87+         if ( isNumeric ( ai ) )  nums ++ ; 
6088    } 
6189
62-     return  ( dcnt  >  ncnt  *  2 ) ; 
90+     return  dats  >  nums  *  2 ; 
91+ } 
92+ 
93+ // return increment to test at most 1000 points, evenly spaced 
94+ function  getIncrement ( len )  { 
95+     return  Math . max ( 1 ,  ( len  -  1 )  /  1000 ) ; 
6396} 
6497
6598// are the (x,y)-values in gd.data mostly text? 
6699// require twice as many DISTINCT categories as distinct numbers 
67- function  category ( a )  { 
68-     // test at most 1000 points 
69-     var  inc  =  Math . max ( 1 ,  ( a . length  -  1 )  /  1000 ) ; 
70-     var  curvenums  =  0 ; 
71-     var  curvecats  =  0 ; 
100+ function  category ( a ,  convertNumeric )  { 
101+     var  len  =  a . length ; 
102+ 
103+     var  inc  =  getIncrement ( len ) ; 
104+     var  nums  =  0 ; 
105+     var  cats  =  0 ; 
72106    var  seen  =  { } ; 
73107
74-     for ( var  i  =  0 ;  i  <  a . length ;  i  +=  inc )  { 
75-         var  ai  =  a [ Math . round ( i ) ] ; 
108+     for ( var  f  =  0 ;  f  <  len ;  f  +=  inc )  { 
109+         var  i  =  round ( f ) ; 
110+         var  ai  =  a [ i ] ; 
76111        var  stri  =  String ( ai ) ; 
77112        if ( seen [ stri ] )  continue ; 
78113        seen [ stri ]  =  1 ; 
79114
80-         if ( typeof  ai  ===  'boolean' )  curvecats ++ ; 
81-         else  if ( Lib . cleanNumber ( ai )  !==  BADNUM )  curvenums ++ ; 
82-         else  if ( typeof  ai  ===  'string' )  curvecats ++ ; 
115+         var  t  =  typeof  ai ; 
116+         if ( t  ===  'boolean' )  cats ++ ; 
117+         else  if ( convertNumeric  ? cleanNumber ( ai )  !==  BADNUM  : t  ===  'number' )  nums ++ ; 
118+         else  if ( t  ===  'string' )  cats ++ ; 
83119    } 
84120
85-     return  curvecats  >  curvenums  *  2 ; 
121+     return  cats  >  nums  *  2 ; 
86122} 
87123
88124// very-loose requirements for multicategory, 
89125// trace modules that should never auto-type to multicategory 
90126// should be declared with 'noMultiCategory' 
91127function  multiCategory ( a )  { 
92-     return  Lib . isArrayOrTypedArray ( a [ 0 ] )  &&  Lib . isArrayOrTypedArray ( a [ 1 ] ) ; 
128+     return  isArrayOrTypedArray ( a [ 0 ] )  &&  isArrayOrTypedArray ( a [ 1 ] ) ; 
93129} 
0 commit comments