import _ from 'lodash' ; import * as dataflowHelper from '@/store/dataflow/helper' ; import Edge from '@/components/edge/edge' ; import store from '@/store' ; import { CreateNodeOptions , DataflowState } from '@/store/dataflow/types' ; import { FlowsenseDef } from '@/store/flowsense/types' ; import { INDEX_COLUMN } from '@/common/constants' ; import { Node } from '@/components/node' ; import { OutputPort , InputPort } from '@/components/port' ; import { SubsetNode } from '@/components/subset-node' ; import { Visualization } from '@/components/visualization' ; import { ejectMarker , InjectedQuery , ejectMappableMarker } from '../helper' ; import { focusNode , focusNodes } from '@/store/interaction/helper' ; import { vectorDistance } from '@/common/vector' ; import FlowsenseUpdateTracker from './tracker' ; export { ejectMarker , ejectMappableMarker , focusNode , focusNodes , } ; const dataflow = ( ) : DataflowState => store . state . dataflow ; const findNodeWithLabel = ( label ) : Node | undefined => { return dataflow ( ) . nodes . filter ( node => node . getLabel ( ) === label ) [ 0 ] ; } ; const findNodeWithType = ( type ) : Node | undefined => { const nodes = dataflow ( ) . nodes . filter ( dataflowNode => dataflowNode . nodeType === type ) ; if ( ! nodes . length ) { return undefined ; } let node = nodes [ 0 ] ; for ( const candidateNode of nodes ) { if ( candidateNode . getActiveness ( ) > node . getActiveness ( ) ) { node = candidateNode ; } } return node ; } ; /**
 * Retrieves a node with the injected label.
 * Panic if the node label cannot be found.
 */ export const getNodeByLabel = ( injectedLabel , query , tracker ) : Node | undefined => { const nodeLabel = ejectMappableMarker ( injectedLabel , query . markerMapping ) . value [ 0 ] ; const foundNode = findNodeWithLabel ( nodeLabel ) ; if ( ! foundNode ) { tracker . cancel ( `cannot find node with label ${ nodeLabel }` ) ; } return foundNode ; } ; /**
 * Retrieves a node with a given type.
 * Panic if such a node cannot be found.
 */ export const getNodeByType = ( injectedType , query , tracker ) : Node | undefined => { const nodeType = ejectMappableMarker ( injectedType , query . markerMapping ) . value [ 0 ] ; const foundNode = findNodeWithType ( nodeType ) ; if ( ! foundNode ) { tracker . cancel ( `cannot find node of type ${ nodeType }` ) ; } return foundNode ; } ; export const getNodeByLabelOrType = ( injected , query , tracker ) : Node | undefined => { if ( injected . match ( /node_type/ ) ) { return getNodeByType ( injected , query , tracker ) ; } else if ( injected . match ( /node_label/ ) ) { return getNodeByLabel ( injected , query , tracker ) ; } else { console . error ( `cannot eject value ${ injected }` ) ; } } ; /**
 * Returns the default sources for a query, excluding the nodes specified in the exceptions.
 */ export const getDefaultSources = ( count = 1 , exceptions ? ) : Node [ ] => { return focusNodes ( ) . filter ( focusedNode => ( exceptions || [ ] ) . indexOf ( focusedNode ) === - 1 ) . slice ( 0 , count ) ; } ; /**
 * Returns the position where Flowsense is activated. This is the position where the diagram should be extended.
 */ const getActivePosition = ( ) : Point => { return { x : store . state . flowsense . activePosition . x , y : store . state . flowsense . activePosition . y } ; } ; interface FlowsenseCreateNodeOptions { createIndex ? : number ; offsetX ? : number ; offsetY ? : number ; } const CREATE_INDEX_X_OFFSET_PX = 100 ; /**
 * Returns a create node options object that includes the position where Flowsense should create new node at.
 */ export const getCreateNodeOptions = ( type , options ? ) : CreateNodeOptions => { options = options || { } ; const position = getActivePosition ( ) ; const createIndex = options . offsetX ? 0 : ( options . createIndex || 0 ) ; return { type , activate : true , dataflowCenterX : position . x + createIndex * CREATE_INDEX_X_OFFSET_PX + ( options . offsetX || 0 ) , dataflowCenterY : position . y + ( options . offsetY || 0 ) } ; } ; /**
 * Provides createNode wrapper.
 */ export const createNode = ( options , nodeSave ? ) : Node => { return dataflowHelper . createNode ( dataflow ( ) , options , nodeSave ) ; } ; /**
 * Provides createEdge wrapper.
 */ export const createEdge = ( sourcePort , targetPort , propagate ) : Edge | null => { return dataflowHelper . createEdge ( dataflow ( ) , sourcePort , targetPort , propagate ) ; } ; /**
 * Provides removeEdge wrapper.
 */ export const removeEdge = ( edge , propagate ) => { dataflowHelper . removeEdge ( dataflow ( ) , edge , propagate ) ; } ; /**
 * Propagates the nodes in the list.
 */ export const propagateNodes = ( nodes ) => { dataflowHelper . propagateNodes ( nodes ) ; } ; /**
 * Returns the column index for a injected column marker based on a given node's input dataset.
 * If the node not have input data, or the column cannot be found on the data, null is returned.
 */ export const getColumnMarkerIndex = ( query , node , injectedColumn ) : number | null => { let columnIndex = injectedColumn === FlowsenseDef . INDEX_COLUMN ? INDEX_COLUMN : null ; if ( injectedColumn !== FlowsenseDef . INDEX_COLUMN && node . hasDataset ( ) ) { const columnName = ejectMappableMarker ( injectedColumn , query . markerMapping ) . value [ 0 ] ; columnIndex = node . getDataset ( ) . getColumnIndex ( columnName ) ; } return columnIndex ; } ; /**
 * Returns indices of all the columns in a source node.
 */ export const getAllColumns = ( node ) : number [ ] => { if ( node . hasDataset ( ) ) { return _ . range ( node . getDataset ( ) . numColumns ( ) ) ; } return [ ] ; } ; const NEARBY_THRESHOLD_PX = window . innerHeight / 4 ; /**
 * Returns a list of nodes that are close to the given node.
 */ export const getNearbyNodes = ( qNode ) : Node [ ] => { const qCenter = qNode . getCenter ( ) ; return dataflow ( ) . nodes . filter ( node => { const center = node . getCenter ( ) ; return vectorDistance ( qCenter , center ) <= NEARBY_THRESHOLD_PX ; } ) ; } ; export const getAllNodes = ( ) : Node [ ] => { return dataflow ( ) . nodes ; } ; export const isVisualization = ( node ) : boolean => { return ( node as Visualization ) . isVisualization ; } ;