@@ -2037,9 +2037,10 @@ plots.didMarginChange = function(margin0, margin1) {
20372037 * keepall: keep data and src
20382038 * @param {String } output If you specify 'object', the result will not be stringified
20392039 * @param {Boolean } useDefaults If truthy, use _fullLayout and _fullData
2040+ * @param {Boolean } includeConfig If truthy, include _context
20402041 * @returns {Object|String }
20412042 */
2042- plots . graphJson = function ( gd , dataonly , mode , output , useDefaults ) {
2043+ plots . graphJson = function ( gd , dataonly , mode , output , useDefaults , includeConfig ) {
20432044 // if the defaults aren't supplied yet, we need to do that...
20442045 if ( ( useDefaults && dataonly && ! gd . _fullData ) ||
20452046 ( useDefaults && ! dataonly && ! gd . _fullLayout ) ) {
@@ -2050,26 +2051,29 @@ plots.graphJson = function(gd, dataonly, mode, output, useDefaults) {
20502051 var layout = ( useDefaults ) ? gd . _fullLayout : gd . layout ;
20512052 var frames = ( gd . _transitionData || { } ) . _frames ;
20522053
2053- function stripObj ( d ) {
2054+ function stripObj ( d , keepFunction ) {
20542055 if ( typeof d === 'function' ) {
2055- return null ;
2056+ return keepFunction ? '_function_' : null ;
20562057 }
20572058 if ( Lib . isPlainObject ( d ) ) {
20582059 var o = { } ;
2059- var v , src ;
2060- for ( v in d ) {
2060+ var src ;
2061+ Object . keys ( d ) . sort ( ) . forEach ( function ( v ) {
20612062 // remove private elements and functions
20622063 // _ is for private, [ is a mistake ie [object Object]
2063- if ( typeof d [ v ] === 'function' ||
2064- [ '_' , '[' ] . indexOf ( v . charAt ( 0 ) ) !== - 1 ) {
2065- continue ;
2064+ if ( [ '_' , '[' ] . indexOf ( v . charAt ( 0 ) ) !== - 1 ) return ;
2065+
2066+ // if a function, add if necessary then move on
2067+ if ( typeof d [ v ] === 'function' ) {
2068+ if ( keepFunction ) o [ v ] = '_function' ;
2069+ return ;
20662070 }
20672071
20682072 // look for src/data matches and remove the appropriate one
20692073 if ( mode === 'keepdata' ) {
20702074 // keepdata: remove all ...src tags
20712075 if ( v . substr ( v . length - 3 ) === 'src' ) {
2072- continue ;
2076+ return ;
20732077 }
20742078 } else if ( mode === 'keepstream' ) {
20752079 // keep sourced data if it's being streamed.
@@ -2078,26 +2082,26 @@ plots.graphJson = function(gd, dataonly, mode, output, useDefaults) {
20782082 src = d [ v + 'src' ] ;
20792083 if ( typeof src === 'string' && src . indexOf ( ':' ) > 0 ) {
20802084 if ( ! Lib . isPlainObject ( d . stream ) ) {
2081- continue ;
2085+ return ;
20822086 }
20832087 }
20842088 } else if ( mode !== 'keepall' ) {
20852089 // keepref: remove sourced data but only
20862090 // if the source tag is well-formed
20872091 src = d [ v + 'src' ] ;
20882092 if ( typeof src === 'string' && src . indexOf ( ':' ) > 0 ) {
2089- continue ;
2093+ return ;
20902094 }
20912095 }
20922096
20932097 // OK, we're including this... recurse into it
2094- o [ v ] = stripObj ( d [ v ] ) ;
2095- }
2098+ o [ v ] = stripObj ( d [ v ] , keepFunction ) ;
2099+ } ) ;
20962100 return o ;
20972101 }
20982102
20992103 if ( Array . isArray ( d ) ) {
2100- return d . map ( stripObj ) ;
2104+ return d . map ( function ( x ) { return stripObj ( x , keepFunction ) ; } ) ;
21012105 }
21022106
21032107 if ( Lib . isTypedArray ( d ) ) {
@@ -2126,6 +2130,8 @@ plots.graphJson = function(gd, dataonly, mode, output, useDefaults) {
21262130
21272131 if ( frames ) obj . frames = stripObj ( frames ) ;
21282132
2133+ if ( includeConfig ) obj . config = stripObj ( gd . _context , true ) ;
2134+
21292135 return ( output === 'object' ) ? obj : JSON . stringify ( obj ) ;
21302136} ;
21312137
0 commit comments