import { CoordinateExtent , EdgeChange , Actions , Getters , State , GraphNode , Node , NodeChange , NodeDimensionChange } from '~/types' ; import { createPositionChange , createSelectionChange , getSelectionChanges , isEdge , isGraphEdge , isGraphNode , isNode , isParentSelected , parseEdge , parseNode , } from '~/utils' ; const getParent = ( root , id ) : GraphNode | undefined => { let node ; root . some ( ( n ) => { if ( n . id === id ) return ( node = n ) ; if ( n . children ) return ( node = getParent ( n . children , id ) ) ; return false ; } ) ; return node ; } ; export const parseChildren = ( n , p , arr , extent , getNode ) => { const parent = typeof p === 'undefined' || typeof p !== 'object' ? getParent ( arr , n . id ) : p ; const parsed = parseNode ( n , extent , { ... getNode ( n . id ) , parentNode : parent , } ) ; arr . push ( parsed ) ; if ( n . children && n . children . length ) { n . children . forEach ( ( c ) => parseChildren ( c , parsed , arr , extent , getNode ) ) ; } } ; export default ( state , getters ) : Actions => { const updateNodePosition = ( { id , diff = { x : 0 , y : 0 } , dragging } ) => { const changes = [ ] ; state . nodes . forEach ( ( node ) => { if ( node . selected ) { if ( ! node . parentNode ) { changes . push ( createPositionChange ( { node , diff , nodeExtent : state . nodeExtent , dragging } ) ) ; } else if ( ! isParentSelected ( node ) ) { changes . push ( createPositionChange ( { node , diff , nodeExtent : state . nodeExtent , dragging } ) ) ; } } else if ( node . id === id ) { changes . push ( createPositionChange ( { node , diff , nodeExtent : state . nodeExtent , dragging } ) ) ; } } ) ; if ( changes . length ) state . hooks . nodesChange . trigger ( changes ) ; } ; const addSelectedNodes = ( nodes ) => { const selectedNodesIds = nodes . map ( ( n ) => n . id ) ; let changedNodes ; if ( state . multiSelectionActive ) changedNodes = selectedNodesIds . map ( ( nodeId ) => createSelectionChange ( nodeId , true ) ) ; else changedNodes = getSelectionChanges ( state . nodes , selectedNodesIds ) ; if ( changedNodes . length ) state . hooks . nodesChange . trigger ( changedNodes ) ; } ; const addSelectedEdges = ( edges ) => { const selectedEdgesIds = edges . map ( ( e ) => e . id ) ; let changedEdges ; if ( state . multiSelectionActive ) changedEdges = selectedEdgesIds . map ( ( nodeId ) => createSelectionChange ( nodeId , true ) ) ; else changedEdges = getSelectionChanges ( state . nodes , selectedEdgesIds ) ; if ( changedEdges . length ) state . hooks . edgesChange . trigger ( changedEdges ) ; } ; const addSelectedElements = ( elements ) => { addSelectedNodes ( elements . filter ( isGraphNode ) ) ; addSelectedEdges ( elements . filter ( isGraphEdge ) ) ; } ; const setMinZoom = ( minZoom ) => { state . d3Zoom ?. scaleExtent ( [ minZoom , state . maxZoom ] ) ; state . minZoom = minZoom ; } ; const setMaxZoom = ( maxZoom ) => { state . d3Zoom ?. scaleExtent ( [ state . minZoom , maxZoom ] ) ; state . maxZoom = maxZoom ; } ; const setTranslateExtent = ( translateExtent ) => { state . d3Zoom ?. translateExtent ( translateExtent ) ; state . translateExtent = translateExtent ; } ; const resetSelectedElements = ( ) => { addSelectedNodes ( [ ] ) ; addSelectedEdges ( [ ] ) ; } ; const setConnectionNodeId = ( { connectionHandleId , connectionHandleType , connectionNodeId , } ) => { state . connectionNodeId = connectionNodeId ; state . connectionHandleId = connectionHandleId ; state . connectionHandleType = connectionHandleType ; } ; const setInteractive = ( isInteractive ) => { state . nodesDraggable = isInteractive ; state . nodesConnectable = isInteractive ; state . elementsSelectable = isInteractive ; } ; const setNodes = ( nodes , extent ? ) => { if ( ! state . initialized && ! nodes . length ) return ; nodes = nodes . flatMap ( ( node ) => { const children = [ ] ; parseChildren ( node , undefined , children , extent ?? state . nodeExtent , getters . getNode . value ) ; return children ; } ) ; state . nodes = < GraphNode [ ] > nodes ; } ; const setEdges = ( edges ) => { if ( ! state . initialized && ! edges . length ) return ; state . edges = edges . map ( ( edge ) => { const sourceNode = getters . getNode . value ( edge . source ) ! ; const targetNode = getters . getNode . value ( edge . target ) ! ; if ( ! sourceNode || typeof sourceNode === 'undefined' ) console . warn ( `couldn't create edge for source id: ${ edge . source }; edge id: ${ edge . id }` ) ; if ( ! targetNode || typeof targetNode === 'undefined' ) console . warn ( `couldn't create edge for target id: ${ edge . target }; edge id: ${ edge . id }` ) ; return { ... parseEdge ( edge , { ... getters . getEdge . value ( edge . id ) , } ) , sourceNode , targetNode , } ; } ) ; } ; const setElements = ( elements , extent ) => { if ( ! state . initialized && ! elements . length ) return ; setNodes ( elements . filter ( isNode ) , extent ) ; setEdges ( elements . filter ( isEdge ) ) ; } ; const setState = ( opts ) => { if ( typeof opts . modelValue !== 'undefined' ) setElements ( opts . modelValue , opts . nodeExtent ?? state . nodeExtent ) ; if ( typeof opts . nodes !== 'undefined' ) setNodes ( opts . nodes , opts . nodeExtent ?? state . nodeExtent ) ; if ( typeof opts . edges !== 'undefined' ) setEdges ( opts . edges ) ; if ( typeof opts . panOnScroll !== 'undefined' ) state . panOnScroll = opts . panOnScroll ; if ( typeof opts . panOnScrollMode !== 'undefined' ) state . panOnScrollMode = opts . panOnScrollMode ; if ( typeof opts . panOnScrollSpeed !== 'undefined' ) state . panOnScrollSpeed = opts . panOnScrollSpeed ; if ( typeof opts . paneMoveable !== 'undefined' ) state . paneMoveable = opts . paneMoveable ; if ( typeof opts . zoomOnScroll !== 'undefined' ) state . zoomOnScroll = opts . zoomOnScroll ; if ( typeof opts . preventScrolling !== 'undefined' ) state . preventScrolling = opts . preventScrolling ; if ( typeof opts . zoomOnDoubleClick !== 'undefined' ) state . zoomOnDoubleClick = opts . zoomOnDoubleClick ; if ( typeof opts . zoomOnPinch !== 'undefined' ) state . zoomOnPinch = opts . zoomOnPinch ; if ( typeof opts . defaultZoom !== 'undefined' ) state . defaultZoom = opts . defaultZoom ; if ( typeof opts . defaultPosition !== 'undefined' ) state . defaultPosition = opts . defaultPosition ; if ( typeof opts . edgeUpdaterRadius !== 'undefined' ) state . edgeUpdaterRadius = opts . edgeUpdaterRadius ; if ( typeof opts . elementsSelectable !== 'undefined' ) state . elementsSelectable = opts . elementsSelectable ; if ( typeof opts . onlyRenderVisibleElements !== 'undefined' ) state . onlyRenderVisibleElements = opts . onlyRenderVisibleElements ; if ( typeof opts . edgesUpdatable !== 'undefined' ) state . edgesUpdatable = opts . edgesUpdatable ; if ( typeof opts . nodesConnectable !== 'undefined' ) state . nodesConnectable = opts . nodesConnectable ; if ( typeof opts . nodesDraggable !== 'undefined' ) state . nodesDraggable = opts . nodesDraggable ; if ( typeof opts . defaultMarkerColor !== 'undefined' ) state . defaultMarkerColor = opts . defaultMarkerColor ; if ( typeof opts . deleteKeyCode !== 'undefined' ) state . deleteKeyCode = opts . deleteKeyCode ; if ( typeof opts . selectionKeyCode !== 'undefined' ) state . selectionKeyCode = opts . selectionKeyCode ; if ( typeof opts . zoomActivationKeyCode !== 'undefined' ) state . zoomActivationKeyCode = opts . zoomActivationKeyCode ; if ( typeof opts . multiSelectionKeyCode !== 'undefined' ) state . multiSelectionKeyCode = opts . multiSelectionKeyCode ; if ( typeof opts . snapToGrid !== 'undefined' ) state . snapToGrid = opts . snapToGrid ; if ( typeof opts . snapGrid !== 'undefined' ) state . snapGrid = opts . snapGrid ; if ( typeof opts . nodeExtent !== 'undefined' ) state . nodeExtent = opts . nodeExtent ; if ( typeof opts . fitViewOnInit !== 'undefined' ) state . fitViewOnInit = opts . fitViewOnInit ; if ( ! state . paneReady ) until ( ( ) => state . d3Zoom ) . not . toBeUndefined ( ) . then ( ( ) => { if ( typeof opts . maxZoom !== 'undefined' ) setMaxZoom ( opts . maxZoom ) ; if ( typeof opts . minZoom !== 'undefined' ) setMinZoom ( opts . minZoom ) ; if ( typeof opts . translateExtent !== 'undefined' ) setTranslateExtent ( opts . translateExtent ) ; } ) ; else { if ( typeof opts . maxZoom !== 'undefined' ) setMaxZoom ( opts . maxZoom ) ; if ( typeof opts . minZoom !== 'undefined' ) setMinZoom ( opts . minZoom ) ; if ( typeof opts . translateExtent !== 'undefined' ) setTranslateExtent ( opts . translateExtent ) ; } if ( ! state . initialized ) state . initialized = true ; } ; return { updateNodePosition , setElements , setNodes , setEdges , addSelectedElements , addSelectedNodes , addSelectedEdges , setMinZoom , setMaxZoom , setTranslateExtent , resetSelectedElements , setConnectionNodeId , setInteractive , setState , } ; } ;