feat(core): add getIncomers, getOutgoers & getConnectedEdges as store actions

This commit is contained in:
braks
2023-10-06 18:00:01 +02:00
committed by Braks
parent 5e888987eb
commit edc7669b18
4 changed files with 95 additions and 20 deletions
+21 -2
View File
@@ -34,9 +34,11 @@ import {
createGraphNodes, createGraphNodes,
createNodeRemoveChange, createNodeRemoveChange,
createSelectionChange, createSelectionChange,
getConnectedEdges, getConnectedEdges as getConnectedEdgesBase,
getDimensions, getDimensions,
getHandleBounds, getHandleBounds,
getIncomers as getIncomersBase,
getOutgoers as getOutgoersBase,
getOverlappingArea, getOverlappingArea,
getSelectionChanges, getSelectionChanges,
isDef, isDef,
@@ -54,7 +56,9 @@ export function useActions(
hooksOn: any, hooksOn: any,
state: State, state: State,
getters: ComputedGetters, getters: ComputedGetters,
// todo: change to a Set
nodeIds: ComputedRef<string[]>, nodeIds: ComputedRef<string[]>,
// todo: change to a Set
edgeIds: ComputedRef<string[]>, edgeIds: ComputedRef<string[]>,
): Actions { ): Actions {
const viewportHelper = useViewport(state, getters) const viewportHelper = useViewport(state, getters)
@@ -65,6 +69,18 @@ export function useActions(
state.hooks.updateNodeInternals.trigger(updateIds) state.hooks.updateNodeInternals.trigger(updateIds)
} }
const getIncomers: Actions['getIncomers'] = (nodeOrId) => {
return getIncomersBase(nodeOrId, state.nodes, state.edges)
}
const getOutgoers: Actions['getOutgoers'] = (nodeOrId) => {
return getOutgoersBase(nodeOrId, state.nodes, state.edges)
}
const getConnectedEdges: Actions['getConnectedEdges'] = (nodesOrId) => {
return getConnectedEdgesBase(nodesOrId, state.edges)
}
const findNode: Actions['findNode'] = (id) => { const findNode: Actions['findNode'] = (id) => {
if (!id) { if (!id) {
return return
@@ -519,7 +535,7 @@ export function useActions(
const edgeChanges: EdgeRemoveChange[] = [] const edgeChanges: EdgeRemoveChange[] = []
function createEdgeRemovalChanges(nodes: Node[]) { function createEdgeRemovalChanges(nodes: Node[]) {
const connections = getConnectedEdges(nodes, state.edges).filter((edge) => (isDef(edge.deletable) ? edge.deletable : true)) const connections = getConnectedEdges(nodes).filter((edge) => (isDef(edge.deletable) ? edge.deletable : true))
edgeChanges.push( edgeChanges.push(
...connections.map((connection) => createEdgeRemoveChange(connection.id, connection.source, connection.target)), ...connections.map((connection) => createEdgeRemoveChange(connection.id, connection.source, connection.target)),
@@ -920,6 +936,9 @@ export function useActions(
setInteractive, setInteractive,
setState, setState,
getIntersectingNodes, getIntersectingNodes,
getIncomers,
getOutgoers,
getConnectedEdges,
isNodeIntersecting, isNodeIntersecting,
panBy, panBy,
fitView: (params) => viewportHelper.value.fitView(params), fitView: (params) => viewportHelper.value.fitView(params),
+2
View File
@@ -31,7 +31,9 @@ function defaultState(): State {
return { return {
vueFlowRef: null, vueFlowRef: null,
viewportRef: null, viewportRef: null,
// todo: change this to a Set
nodes: [], nodes: [],
// todo: change this to a Set
edges: [], edges: [],
nodeTypes: {}, nodeTypes: {},
edgeTypes: {}, edgeTypes: {},
+6
View File
@@ -275,6 +275,12 @@ export interface Actions extends ViewportFunctions {
getIntersectingNodes: GetIntersectingNodes getIntersectingNodes: GetIntersectingNodes
/** check if a node is intersecting with a defined area */ /** check if a node is intersecting with a defined area */
isNodeIntersecting: IsNodeIntersecting isNodeIntersecting: IsNodeIntersecting
/** get a node's incomers */
getIncomers: (nodeOrId: Node | string) => GraphNode[]
/** get a node's outgoers */
getOutgoers: (nodeOrId: Node | string) => GraphNode[]
/** get a node's connected edges */
getConnectedEdges: (nodesOrId: Node[] | string) => GraphEdge[]
/** pan the viewport; return indicates if a transform has happened or not */ /** pan the viewport; return indicates if a transform has happened or not */
panBy: (delta: XYPosition) => boolean panBy: (delta: XYPosition) => boolean
+66 -18
View File
@@ -9,6 +9,7 @@ import type {
Dimensions, Dimensions,
Edge, Edge,
EdgeMarkerType, EdgeMarkerType,
Element,
ElementData, ElementData,
Elements, Elements,
FlowElements, FlowElements,
@@ -151,24 +152,63 @@ export function parseEdge(edge: Edge, defaults: Partial<GraphEdge> = {}): GraphE
return Object.assign({}, defaults, edge, { id: edge.id.toString() }) as GraphEdge return Object.assign({}, defaults, edge, { id: edge.id.toString() }) as GraphEdge
} }
function getConnectedElements<T extends Elements = FlowElements>( function getConnectedElements<T extends Node = Node>(
nodeOrId: Node | { id: string } | string, nodeOrId: Node | { id: string } | string,
elements: T, nodes: T[],
edges: Edge[],
dir: 'source' | 'target', dir: 'source' | 'target',
): T extends FlowElements ? GraphNode[] : Node[] { ): T[] {
const id = isString(nodeOrId) ? nodeOrId : nodeOrId.id const id = isString(nodeOrId) ? nodeOrId : nodeOrId.id
const connectedIds = new Set()
const origin = dir === 'source' ? 'target' : 'source' const origin = dir === 'source' ? 'target' : 'source'
const ids = elements.filter((e) => isEdge(e) && e[origin] === id).map((e) => isEdge(e) && e[dir])
return elements.filter((e) => ids.includes(e.id)) as T extends FlowElements ? GraphNode[] : Node[] edges.forEach((edge) => {
} if (edge[origin] === id) {
export function getOutgoers<T extends Elements = FlowElements>(nodeOrId: Node | { id: string } | string, elements: T) { connectedIds.add(edge[dir])
return getConnectedElements(nodeOrId, elements, 'target') }
})
return nodes.filter((n) => connectedIds.has(n.id))
} }
export function getIncomers<T extends Elements = FlowElements>(nodeOrId: Node | { id: string } | string, elements: T) { export function getOutgoers<N extends Node>(nodeOrId: Node | { id: string } | string, nodes: N[], edges: Edge[]): N[]
return getConnectedElements(nodeOrId, elements, 'source') export function getOutgoers<T extends Elements>(
nodeOrId: Node | { id: string } | string,
elements: T,
): T extends FlowElements ? GraphNode[] : Node[]
export function getOutgoers(...args: any[]) {
if (args.length === 3) {
const [nodeOrId, nodes, edges] = args
return getConnectedElements(nodeOrId, nodes, edges, 'target')
}
const [nodeOrId, elements] = args
const node: Node = isString(nodeOrId) ? { id: nodeOrId } : nodeOrId
const outgoers = elements.filter((el: Element) => isEdge(el) && el.source === node.id)
return outgoers.map((edge: Edge) => elements.find((el: Element) => isNode(el) && el.id === edge.target))
}
export function getIncomers<N extends Node>(nodeOrId: Node | { id: string } | string, nodes: N[], edges: Edge[]): N[]
export function getIncomers<T extends Elements>(
nodeOrId: Node | { id: string } | string,
elements: T,
): T extends FlowElements ? GraphNode[] : Node[]
export function getIncomers(...args: any[]) {
if (args.length === 3) {
const [nodeOrId, nodes, edges] = args
return getConnectedElements(nodeOrId, nodes, edges, 'source')
}
const [nodeOrId, elements] = args
const node: Node = isString(nodeOrId) ? { id: nodeOrId } : nodeOrId
const incomers = elements.filter((el: Element) => isEdge(el) && el.target === node.id)
return incomers.map((edge: Edge) => elements.find((el: Element) => isNode(el) && el.id === edge.source))
} }
export function getEdgeId({ source, sourceHandle, target, targetHandle }: Connection) { export function getEdgeId({ source, sourceHandle, target, targetHandle }: Connection) {
@@ -364,26 +404,34 @@ export function getNodesInside(
}) })
} }
export function getConnectedEdges<N extends Node | { id: string } | string, E extends Edge>(nodes: N[], edges: E[]) { export function getConnectedEdges<E extends Edge>(nodesOrId: Node[] | string, edges: E[]) {
const nodeIds = nodes.map((node) => (isString(node) ? node : node.id)) const nodeIds = new Set()
return edges.filter((edge) => nodeIds.includes(edge.source) || nodeIds.includes(edge.target)) if (isString(nodesOrId)) {
nodeIds.add(nodesOrId)
} else if (nodesOrId.length >= 1) {
nodesOrId.forEach((n) => nodeIds.add(n.id))
}
return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target))
} }
export function getConnectedNodes<N extends Node | { id: string } | string, E extends Edge>(nodes: N[], edges: E[]) { export function getConnectedNodes<N extends Node | { id: string } | string>(nodes: N[], edges: Edge[]) {
const nodeIds = nodes.map((node) => (isString(node) ? node : node.id)) const nodeIds = new Set()
nodes.forEach((node) => nodeIds.add(isString(node) ? node : node.id))
const connectedNodeIds = edges.reduce((acc, edge) => { const connectedNodeIds = edges.reduce((acc, edge) => {
if (nodeIds.includes(edge.source)) { if (nodeIds.has(edge.source)) {
acc.add(edge.target) acc.add(edge.target)
} }
if (nodeIds.includes(edge.target)) { if (nodeIds.has(edge.target)) {
acc.add(edge.source) acc.add(edge.source)
} }
return acc return acc
}, new Set<string>()) }, new Set())
return nodes.filter((node) => connectedNodeIds.has(isString(node) ? node : node.id)) return nodes.filter((node) => connectedNodeIds.has(isString(node) ? node : node.id))
} }