@@ -17,6 +17,7 @@ var axes = module.exports = {};
1717
1818axes . layoutAttributes = require ( './layout_attributes' ) ;
1919
20+ axes . setConvert = require ( './set_convert' ) ;
2021
2122var utils = require ( './utils' ) ;
2223axes . id2name = utils . id2name ;
@@ -533,238 +534,6 @@ axes.category = function(a) {
533534 return curvecats > curvenums * 2 ;
534535} ;
535536
536- // cleanDatum: removes characters
537- // same replace criteria used in the grid.js:scrapeCol
538- // but also handling dates, numbers, and NaN, null, Infinity etc
539- axes . cleanDatum = function ( c ) {
540- try {
541- if ( typeof c === 'object' && c !== null && c . getTime ) {
542- return Plotly . Lib . ms2DateTime ( c ) ;
543- }
544- if ( typeof c !== 'string' && ! isNumeric ( c ) ) {
545- return '' ;
546- }
547- c = c . toString ( ) . replace ( / [ ' " % , $ # ] / g, '' ) ;
548- } catch ( e ) {
549- console . log ( e , c ) ;
550- }
551- return c ;
552- } ;
553-
554- // setConvert: define the conversion functions for an axis
555- // data is used in 4 ways:
556- // d: data, in whatever form it's provided
557- // c: calcdata: turned into numbers, but not linearized
558- // l: linearized - same as c except for log axes (and other
559- // mappings later?) this is used by ranges, and when we
560- // need to know if it's *possible* to show some data on
561- // this axis, without caring about the current range
562- // p: pixel value - mapped to the screen with current size and zoom
563- // setAxConvert creates/updates these conversion functions
564- // also clears the autorange bounds ._min and ._max
565- // and the autotick constraints ._minDtick, ._forceTick0,
566- // and looks for date ranges that aren't yet in numeric format
567- axes . setConvert = function ( ax ) {
568- // clipMult: how many axis lengths past the edge do we render?
569- // for panning, 1-2 would suffice, but for zooming more is nice.
570- // also, clipping can affect the direction of lines off the edge...
571- var clipMult = 10 ;
572-
573- function toLog ( v , clip ) {
574- if ( v > 0 ) return Math . log ( v ) / Math . LN10 ;
575-
576- else if ( v <= 0 && clip && ax . range && ax . range . length === 2 ) {
577- // clip NaN (ie past negative infinity) to clipMult axis
578- // length past the negative edge
579- var r0 = ax . range [ 0 ] ,
580- r1 = ax . range [ 1 ] ;
581- return 0.5 * ( r0 + r1 - 3 * clipMult * Math . abs ( r0 - r1 ) ) ;
582- }
583-
584- else return axes . BADNUM ;
585- }
586- function fromLog ( v ) { return Math . pow ( 10 , v ) ; }
587- function num ( v ) { return isNumeric ( v ) ? Number ( v ) : axes . BADNUM ; }
588-
589- ax . c2l = ( ax . type === 'log' ) ? toLog : num ;
590- ax . l2c = ( ax . type === 'log' ) ? fromLog : num ;
591- ax . l2d = function ( v ) { return ax . c2d ( ax . l2c ( v ) ) ; } ;
592- ax . p2d = function ( v ) { return ax . l2d ( ax . p2l ( v ) ) ; } ;
593-
594- // set scaling to pixels
595- ax . setScale = function ( ) {
596- var gs = ax . _td . _fullLayout . _size ,
597- i ;
598-
599- // TODO cleaner way to handle this case
600- if ( ! ax . _categories ) ax . _categories = [ ] ;
601-
602- // make sure we have a domain (pull it in from the axis
603- // this one is overlaying if necessary)
604- if ( ax . overlaying ) {
605- var ax2 = axes . getFromId ( ax . _td , ax . overlaying ) ;
606- ax . domain = ax2 . domain ;
607- }
608-
609- // make sure we have a range (linearized data values)
610- // and that it stays away from the limits of javascript numbers
611- if ( ! ax . range || ax . range . length !== 2 || ax . range [ 0 ] === ax . range [ 1 ] ) {
612- ax . range = [ - 1 , 1 ] ;
613- }
614- for ( i = 0 ; i < 2 ; i ++ ) {
615- if ( ! isNumeric ( ax . range [ i ] ) ) {
616- ax . range [ i ] = isNumeric ( ax . range [ 1 - i ] ) ?
617- ( ax . range [ 1 - i ] * ( i ? 10 : 0.1 ) ) :
618- ( i ? 1 : - 1 ) ;
619- }
620-
621- if ( ax . range [ i ] < - ( Number . MAX_VALUE / 2 ) ) {
622- ax . range [ i ] = - ( Number . MAX_VALUE / 2 ) ;
623- }
624- else if ( ax . range [ i ] > Number . MAX_VALUE / 2 ) {
625- ax . range [ i ] = Number . MAX_VALUE / 2 ;
626- }
627-
628- }
629-
630- if ( ax . _id . charAt ( 0 ) === 'y' ) {
631- ax . _offset = gs . t + ( 1 - ax . domain [ 1 ] ) * gs . h ;
632- ax . _length = gs . h * ( ax . domain [ 1 ] - ax . domain [ 0 ] ) ;
633- ax . _m = ax . _length / ( ax . range [ 0 ] - ax . range [ 1 ] ) ;
634- ax . _b = - ax . _m * ax . range [ 1 ] ;
635- }
636- else {
637- ax . _offset = gs . l + ax . domain [ 0 ] * gs . w ;
638- ax . _length = gs . w * ( ax . domain [ 1 ] - ax . domain [ 0 ] ) ;
639- ax . _m = ax . _length / ( ax . range [ 1 ] - ax . range [ 0 ] ) ;
640- ax . _b = - ax . _m * ax . range [ 0 ] ;
641- }
642-
643- if ( ! isFinite ( ax . _m ) || ! isFinite ( ax . _b ) ) {
644- Plotly . Lib . notifier (
645- 'Something went wrong with axis scaling' ,
646- 'long' ) ;
647- ax . _td . _replotting = false ;
648- throw new Error ( 'axis scaling' ) ;
649- }
650- } ;
651-
652- ax . l2p = function ( v ) {
653- if ( ! isNumeric ( v ) ) return axes . BADNUM ;
654- // include 2 fractional digits on pixel, for PDF zooming etc
655- return d3 . round ( Plotly . Lib . constrain ( ax . _b + ax . _m * v ,
656- - clipMult * ax . _length , ( 1 + clipMult ) * ax . _length ) , 2 ) ;
657- } ;
658-
659- ax . p2l = function ( px ) { return ( px - ax . _b ) / ax . _m ; } ;
660-
661- ax . c2p = function ( v , clip ) { return ax . l2p ( ax . c2l ( v , clip ) ) ; } ;
662- ax . p2c = function ( px ) { return ax . l2c ( ax . p2l ( px ) ) ; } ;
663-
664- if ( [ 'linear' , 'log' , '-' ] . indexOf ( ax . type ) !== - 1 ) {
665- ax . c2d = num ;
666- ax . d2c = function ( v ) {
667- v = axes . cleanDatum ( v ) ;
668- return isNumeric ( v ) ? Number ( v ) : axes . BADNUM ;
669- } ;
670- ax . d2l = function ( v , clip ) {
671- if ( ax . type === 'log' ) return ax . c2l ( ax . d2c ( v ) , clip ) ;
672- else return ax . d2c ( v ) ;
673- } ;
674- }
675- else if ( ax . type === 'date' ) {
676- ax . c2d = function ( v ) {
677- return isNumeric ( v ) ? Plotly . Lib . ms2DateTime ( v ) : axes . BADNUM ;
678- } ;
679-
680- ax . d2c = function ( v ) {
681- return ( isNumeric ( v ) ) ? Number ( v ) : Plotly . Lib . dateTime2ms ( v ) ;
682- } ;
683-
684- ax . d2l = ax . d2c ;
685-
686- // check if date strings or js date objects are provided for range
687- // and convert to ms
688- if ( ax . range && ax . range . length > 1 ) {
689- try {
690- var ar1 = ax . range . map ( Plotly . Lib . dateTime2ms ) ;
691- if ( ! isNumeric ( ax . range [ 0 ] ) && isNumeric ( ar1 [ 0 ] ) ) {
692- ax . range [ 0 ] = ar1 [ 0 ] ;
693- }
694- if ( ! isNumeric ( ax . range [ 1 ] ) && isNumeric ( ar1 [ 1 ] ) ) {
695- ax . range [ 1 ] = ar1 [ 1 ] ;
696- }
697- }
698- catch ( e ) { console . log ( e , ax . range ) ; }
699- }
700- }
701- else if ( ax . type === 'category' ) {
702-
703- ax . c2d = function ( v ) {
704- return ax . _categories [ Math . round ( v ) ] ;
705- } ;
706-
707- ax . d2c = function ( v ) {
708- // create the category list
709- // this will enter the categories in the order it
710- // encounters them, ie all the categories from the
711- // first data set, then all the ones from the second
712- // that aren't in the first etc.
713- // TODO: sorting options - do the sorting
714- // progressively here as we insert?
715- if ( ax . _categories . indexOf ( v ) === - 1 ) ax . _categories . push ( v ) ;
716-
717- var c = ax . _categories . indexOf ( v ) ;
718- return c === - 1 ? axes . BADNUM : c ;
719- } ;
720-
721- ax . d2l = ax . d2c ;
722- }
723-
724- // makeCalcdata: takes an x or y array and converts it
725- // to a position on the axis object "ax"
726- // inputs:
727- // tdc - a data object from td.data
728- // axletter - a string, either 'x' or 'y', for which item
729- // to convert (TODO: is this now always the same as
730- // the first letter of ax._id?)
731- // in case the expected data isn't there, make a list of
732- // integers based on the opposite data
733- ax . makeCalcdata = function ( tdc , axletter ) {
734- var arrayIn , arrayOut , i ;
735-
736- if ( axletter in tdc ) {
737- arrayIn = tdc [ axletter ] ;
738- arrayOut = new Array ( arrayIn . length ) ;
739-
740- for ( i = 0 ; i < arrayIn . length ; i ++ ) arrayOut [ i ] = ax . d2c ( arrayIn [ i ] ) ;
741- }
742- else {
743- var v0 = ( ( axletter + '0' ) in tdc ) ?
744- ax . d2c ( tdc [ axletter + '0' ] ) : 0 ,
745- dv = ( tdc [ 'd' + axletter ] ) ?
746- Number ( tdc [ 'd' + axletter ] ) : 1 ;
747-
748- // the opposing data, for size if we have x and dx etc
749- arrayIn = tdc [ { x : 'y' , y : 'x' } [ axletter ] ] ;
750- arrayOut = new Array ( arrayIn . length ) ;
751-
752- for ( i = 0 ; i < arrayIn . length ; i ++ ) arrayOut [ i ] = v0 + i * dv ;
753- }
754- return arrayOut ;
755- } ;
756-
757- // for autoranging: arrays of objects:
758- // {val: axis value, pad: pixel padding}
759- // on the low and high sides
760- ax . _min = [ ] ;
761- ax . _max = [ ] ;
762-
763- // and for bar charts and box plots: reset forced minimum tick spacing
764- ax . _minDtick = null ;
765- ax . _forceTick0 = null ;
766- } ;
767-
768537// incorporate a new minimum difference and first tick into
769538// forced
770539axes . minDtick = function ( ax , newDiff , newFirst , allow ) {
0 commit comments