feat(core): add getIncomers, getOutgoers & getConnectedEdges as store actions
This commit is contained in:
@@ -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),
|
||||||
|
|||||||
@@ -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: {},
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user