import { Map } from 'immutable' ; import { zoomIdentity } from 'd3' ; import { FLOWDESIGNER_FLOW_ADD_ELEMENTS , FLOWDESIGNER_FLOW_RESET , FLOWDESIGNER_FLOW_LOAD , FLOWDESIGNER_FLOW_SET_ZOOM , FLOWDESIGNER_FLOW_ZOOM_IN , FLOWDESIGNER_FLOW_ZOOM_OUT , FLOWDESIGNER_PAN_TO , FLOWDESIGNER_NODETYPE_SET , } from '../constants/flowdesigner.constants' ; import nodesReducer from './node.reducer' ; import linksReducer from './link.reducer' ; import portsReducer from './port.reducer' ; import nodeTypeReducer from './nodeType.reducer' ; import { State , NodeRecord , Id , LinkRecord , PortRecord } from '../customTypings/index.d' ; export const defaultState = Map ( { nodes : Map < Id , NodeRecord > ( ) , links : Map < Id , LinkRecord > ( ) , ports : Map < Id , PortRecord > ( ) , out : Map < Id , Map < Id , Id > > ( ) , in : Map < Id , Map < Id , Id > > ( ) , childrens : Map < Id , Map < Id , Id > > ( ) , parents : Map < Id , Map < Id , Id > > ( ) , nodeTypes : Map < string , any > ( ) , transform : { k : 1 , x : 0 , y : 0 } , transformToApply : undefined , } ) ; function combinedReducer ( state = defaultState , action ) { return [ nodesReducer , linksReducer , portsReducer , nodeTypeReducer ] . reduce ( ( cumulatedState , subReducer ) => subReducer ( cumulatedState , action ) , state ) ; } enum ZoomDirection { IN = 'IN' , OUT = 'OUT' } const DEFAULT_ZOOM_SCALE_STEP = 0.1 ; param currentZoom param zoomDirection param step returns example function calculateZoomScale ( currentZoom , zoomDirection , step ) { let zoomValue ; if ( zoomDirection === ZoomDirection . IN ) { zoomValue = Math . floor ( ( currentZoom + step ) / step ) * step ; } else { zoomValue = Math . ceil ( ( currentZoom - step ) / step ) * step ; } if ( zoomValue < step ) zoomValue = step ; return zoomValue ; } export function reducer ( state , action ) { switch ( action . type ) { case FLOWDESIGNER_FLOW_ADD_ELEMENTS : return action . listOfActionCreation . reduce ( ( cumulativeState , actionCreation ) => combinedReducer ( cumulativeState , actionCreation ) , state ) ; case FLOWDESIGNER_FLOW_RESET : return defaultState . set ( 'nodeTypes' , state . get ( 'nodeTypes' ) ) ; case FLOWDESIGNER_FLOW_LOAD : return action . listOfActionCreation . reduce ( ( cumulativeState , actionCreation ) => combinedReducer ( cumulativeState , actionCreation ) , defaultState . set ( 'nodeTypes' , state . get ( 'nodeTypes' ) ) ) ; case FLOWDESIGNER_FLOW_SET_ZOOM : return state . set ( 'transform' , action . transform ) ; case FLOWDESIGNER_FLOW_ZOOM_IN : return state . set ( 'transformToApply' , zoomIdentity . translate ( state . get ( 'transform' ) . x , state . get ( 'transform' ) . y ) . scale ( calculateZoomScale ( state . get ( 'transform' ) . k , ZoomDirection . IN , action . scale || DEFAULT_ZOOM_SCALE_STEP ) ) ) ; case FLOWDESIGNER_FLOW_ZOOM_OUT : return state . set ( 'transformToApply' , zoomIdentity . translate ( state . get ( 'transform' ) . x , state . get ( 'transform' ) . y ) . scale ( calculateZoomScale ( state . get ( 'transform' ) . k , ZoomDirection . OUT , action . scale || DEFAULT_ZOOM_SCALE_STEP ) ) ) ; case FLOWDESIGNER_PAN_TO : return state . update ( 'transformToApply' , ( ) => zoomIdentity . translate ( state . get ( 'transform' ) . x , state . get ( 'transform' ) . y ) . scale ( state . get ( 'transform' ) . k ) . scale ( 1 / state . get ( 'transform' ) . k ) . translate ( - ( state . get ( 'transform' ) . x + action . x ) , - ( state . get ( 'transform' ) . y + action . y ) ) ) ; default : return combinedReducer ( state , action ) ; } } params params return { object } export function calculatePortsPosition ( state , action ) { let nodes = [ ] ; if ( ( /FLOWDESIGNER_NODE_/ . exec ( action . type ) && action . type !== 'FLOWDESIGNER_NODE_REMOVE' ) || ( /FLOWDESIGNER_PORT_/ . exec ( action . type ) && action . type !== 'FLOWDESIGNER_PORT_REMOVE' ) || /FLOWDESIGNER.FLOW_/ . exec ( action . type ) || action . type === FLOWDESIGNER_NODETYPE_SET ) { if ( action . nodeId ) { nodes . push ( state . getIn ( [ 'nodes' , action . nodeId ] ) ) ; } else if ( action . portId ) { nodes . push ( state . getIn ( [ 'nodes' ] , state . getIn ( [ 'ports' , action . portId ] ) . nodeId ) ) ; } else { nodes = state . get ( 'nodes' ) ; } return nodes . reduce ( ( cumulativeState , node ) => { const nodeType = node . getNodeType ( ) ; const ports = state . get ( 'ports' ) . filter ( ( port ) => port . nodeId === node . id ) ; const component = state . getIn ( [ 'nodeTypes' , nodeType , 'component' ] ) ; if ( component ) { const calculatePortPosition = component . calculatePortPosition ; if ( calculatePortPosition ) { return cumulativeState . mergeIn ( [ 'ports' ] , calculatePortPosition ( ports , node . getPosition ( ) , node . getSize ( ) ) ) ; } } return state ; } , state ) ; } return state ; } function flowDesignerReducer ( state , action ) { let newState = reducer ( state , action ) ; newState = calculatePortsPosition ( newState , action ) ; return newState ; } export default flowDesignerReducer ;