import { each , isArray , isString } from '@antv/util' ; import Behavior from '../../behavior/behavior' ; import { IBehaviorOption } from '../../interface/behavior' ; import { IAbstractGraph } from '../../interface/graph' ; import { ModeType , Modes } from '../../types' ; export default class ModeController { private graph : IAbstractGraph ; public destroyed : boolean ; private type { Modes } memberof public modes : Modes ; private type { string } memberof public mode : string ; private currentBehaves : IBehaviorOption [ ] ; constructor ( graph ) { this . graph = graph ; this . destroyed = false ; this . modes = graph . get ( 'modes' ) || { default : [ ] , } ; this . formatModes ( ) ; this . mode = graph . get ( 'defaultMode' ) || 'default' ; this . currentBehaves = [ ] ; this . setMode ( this . mode ) ; } private formatModes ( ) { const { modes } = this ; each ( modes , mode => { each ( mode , ( behavior , i ) => { if ( isString ( behavior ) ) { mode [ i ] = { type : behavior } ; } } ) ; } ) ; } private setBehaviors ( mode ) { const { graph } = this ; const behaviors = this . modes [ mode ] ; const behaves = [ ] ; let behave ; each ( behaviors || [ ] , behavior => { const BehaviorInstance = Behavior . getBehavior ( behavior . type || behavior ) ; if ( ! BehaviorInstance ) { return ; } behave = new BehaviorInstance ( behavior ) ; if ( behave ) { behave . bind ( graph as IAbstractGraph ) ; behaves . push ( behave ) ; } } ) ; this . currentBehaves = behaves ; } private static mergeBehaviors ( modeBehaviors , behaviors ) { each ( behaviors , behavior => { if ( modeBehaviors . indexOf ( behavior ) < 0 ) { if ( isString ( behavior ) ) { behavior = { type : behavior } ; } modeBehaviors . push ( behavior ) ; } } ) ; return modeBehaviors ; } private static filterBehaviors ( modeBehaviors , behaviors ) { const result = [ ] ; modeBehaviors . forEach ( behavior => { let type = '' ; if ( isString ( behavior ) ) { type = behavior ; } else { type = behavior . type ; } if ( behaviors . indexOf ( type ) < 0 ) { result . push ( behavior ) ; } } ) ; return result ; } public setMode ( mode ) { const { modes , graph } = this ; const current = mode ; const behaviors = modes [ current ] ; if ( ! behaviors ) { return ; } graph . emit ( 'beforemodechange' , { mode } ) ; each ( this . currentBehaves , behave => { if ( behave . delegate ) behave . delegate . remove ( ) ; behave . unbind ( graph ) ; } ) ; this . setBehaviors ( current ) ; graph . emit ( 'aftermodechange' , { mode } ) ; this . mode = mode ; } public getMode ( ) { return this . mode ; } param { ModeType [ ] } behaviors param { ( ModeType [ ] | ModeType ) } modes param { boolean } isAdd returns { Mode } memberof public manipulateBehaviors ( behaviors , modes , isAdd ) { let behaves ; if ( ! isArray ( behaviors ) ) { behaves = [ behaviors ] ; } else { behaves = behaviors ; } if ( isArray ( modes ) ) { each ( modes , mode => { if ( ! this . modes [ mode ] ) { if ( isAdd ) { this . modes [ mode ] = behaves ; } } else if ( isAdd ) { this . modes [ mode ] = ModeController . mergeBehaviors ( this . modes [ mode ] || [ ] , behaves ) ; } else { this . modes [ mode ] = ModeController . filterBehaviors ( this . modes [ mode ] || [ ] , behaves ) ; } } ) ; return this ; } let currentMode = modes ; if ( ! modes ) { currentMode = this . mode ; } if ( ! this . modes [ currentMode ] ) { if ( isAdd ) { this . modes [ currentMode ] = behaves ; } } if ( isAdd ) { this . modes [ currentMode ] = ModeController . mergeBehaviors ( this . modes [ currentMode ] || [ ] , behaves ) ; } else { this . modes [ currentMode ] = ModeController . filterBehaviors ( this . modes [ currentMode ] || [ ] , behaves ) ; } this . formatModes ( ) ; this . setMode ( this . mode ) ; return this ; } param { string | ModeOption | ModeType } behavior param { string | string [ ] } modes return { Graph } public updateBehavior ( behavior , newCfg , mode ? ) { if ( isString ( behavior ) ) { behavior = { type : behavior } ; } let behaviorSet = [ ] ; if ( ! mode || mode === this . mode || mode === 'default' ) { behaviorSet = this . currentBehaves ; if ( ! behaviorSet || ! behaviorSet . length ) { console . warn ( 'Update behavior failed! There is no behaviors in this mode on the graph.' ) ; return this ; } const length = behaviorSet . length ; for ( let i = 0 ; i < length ; i ++ ) { const behave = behaviorSet [ i ] ; if ( behave . type === behavior . type ) { behave . updateCfg ( newCfg ) ; return this ; } if ( i === length - 1 ) console . warn ( 'Update behavior failed! There is no such behavior in the mode' ) ; } } else { behaviorSet = this . modes [ mode ] ; if ( ! behaviorSet || ! behaviorSet . length ) { console . warn ( 'Update behavior failed! There is no behaviors in this mode on the graph.' ) ; return this ; } const length = behaviorSet . length ; for ( let i = 0 ; i < length ; i ++ ) { let behave = behaviorSet [ i ] ; if ( behave . type === behavior . type || behave === behavior . type ) { if ( behave === behavior . type ) behave = { type : behave } ; Object . assign ( behave , newCfg ) ; behaviorSet [ i ] = behave ; return this ; } if ( i === length - 1 ) console . warn ( 'Update behavior failed! There is no such behavior in the mode' ) ; } } return this ; } public destroy ( ) { ( this . graph as IAbstractGraph | null ) = null ; ( this . modes as Modes | null ) = null ; ( this . currentBehaves as IBehaviorOption [ ] | null ) = null ; this . destroyed = true ; } }