@@ -455,7 +455,7 @@ function getParent(attr) {
455455 if ( tail > 0 ) return attr . substr ( 0 , tail ) ;
456456}
457457
458- /*
458+ /**
459459 * hasParent: does an attribute object contain a parent of the given attribute?
460460 * for example, given 'images[2].x' do we also have 'images' or 'images[2]'?
461461 *
@@ -475,6 +475,7 @@ exports.hasParent = function (aobj, attr) {
475475 return false ;
476476} ;
477477
478+ const AX_LETTERS = [ 'x' , 'y' , 'z' ] ;
478479/**
479480 * Empty out types for all axes containing these traces so we auto-set them again
480481 *
@@ -483,12 +484,11 @@ exports.hasParent = function (aobj, attr) {
483484 * @param {object } layoutUpdate: any update being done concurrently to the layout,
484485 * which may supercede clearing the axis types
485486 */
486- var axLetters = [ 'x' , 'y' , 'z' ] ;
487487exports . clearAxisTypes = function ( gd , traces , layoutUpdate ) {
488488 for ( var i = 0 ; i < traces . length ; i ++ ) {
489489 var trace = gd . _fullData [ i ] ;
490490 for ( var j = 0 ; j < 3 ; j ++ ) {
491- var ax = getFromTrace ( gd , trace , axLetters [ j ] ) ;
491+ var ax = getFromTrace ( gd , trace , AX_LETTERS [ j ] ) ;
492492
493493 // do not clear log type - that's never an auto result so must have been intentional
494494 if ( ax && ax . type !== 'log' ) {
@@ -507,3 +507,32 @@ exports.clearAxisTypes = function (gd, traces, layoutUpdate) {
507507 }
508508 }
509509} ;
510+
511+ /**
512+ * Check if a collection (object or array) has changed given two versions of
513+ * the collection: old and new.
514+ *
515+ * @param {Object|Array } oldCollection: Old version of collection to compare
516+ * @param {Object|Array } newCollection: New version of collection to compare
517+ */
518+ const hasCollectionChanged = ( oldCollection , newCollection ) => {
519+ const isArrayOrObject = ( ...vals ) => vals . every ( ( v ) => Lib . isPlainObject ( v ) ) || vals . every ( ( v ) => Array . isArray ( v ) ) ;
520+ if ( [ oldCollection , newCollection ] . every ( ( a ) => Array . isArray ( a ) ) ) {
521+ if ( oldCollection . length !== newCollection . length ) return true ;
522+
523+ return oldCollection . some ( ( oldVal , i ) => {
524+ const newVal = newCollection [ i ] ;
525+ if ( oldVal !== newVal ) return isArrayOrObject ( oldVal , newVal ) ? hasCollectionChanged ( oldVal , newVal ) : true ;
526+ } ) ;
527+ } else {
528+ if ( Object . keys ( oldCollection ) . length !== Object . keys ( newCollection ) . length ) return true ;
529+
530+ return Object . keys ( oldCollection ) . some ( ( k ) => {
531+ if ( k . startsWith ( '_' ) ) return false ;
532+ const oldVal = oldCollection [ k ] ;
533+ const newVal = newCollection [ k ] ;
534+ if ( oldVal !== newVal ) return isArrayOrObject ( oldVal , newVal ) ? hasCollectionChanged ( oldVal , newVal ) : true ;
535+ } ) ;
536+ }
537+ } ;
538+ exports . hasCollectionChanged = hasCollectionChanged ;
0 commit comments