refactor(core): replace array fns

This commit is contained in:
braks
2024-05-31 16:09:34 +02:00
committed by Braks
parent ac5e69b2c8
commit 02f3ca2ba0
7 changed files with 351 additions and 225 deletions
@@ -21,27 +21,28 @@ export function useUpdateNodePositions() {
const positionDiffX = positionDiff.x * xVelo * factor const positionDiffX = positionDiff.x * xVelo * factor
const positionDiffY = positionDiff.y * yVelo * factor const positionDiffY = positionDiff.y * yVelo * factor
const nodeUpdates = getSelectedNodes.value const nodeUpdates: NodeDragItem[] = []
.filter((n) => n.draggable || (nodesDraggable && typeof n.draggable === 'undefined')) for (const node of getSelectedNodes.value) {
.map((n) => { if (node.draggable || (nodesDraggable && typeof node.draggable === 'undefined')) {
const nextPosition = { x: n.computedPosition.x + positionDiffX, y: n.computedPosition.y + positionDiffY } const nextPosition = { x: node.computedPosition.x + positionDiffX, y: node.computedPosition.y + positionDiffY }
const { computedPosition } = calcNextPosition( const { computedPosition } = calcNextPosition(
n, node,
nextPosition, nextPosition,
emits.error, emits.error,
nodeExtent.value, nodeExtent.value,
n.parentNode ? findNode(n.parentNode) : undefined, node.parentNode ? findNode(node.parentNode) : undefined,
) )
return { nodeUpdates.push({
id: n.id, id: node.id,
position: computedPosition, position: computedPosition,
from: n.position, from: node.position,
distance: { x: positionDiff.x, y: positionDiff.y }, distance: { x: positionDiff.x, y: positionDiff.y },
dimensions: n.dimensions, dimensions: node.dimensions,
} as NodeDragItem })
}) }
}
updateNodePositions(nodeUpdates, true, false) updateNodePositions(nodeUpdates, true, false)
} }
@@ -132,15 +132,16 @@ export function useViewportHelper(state: State) {
duration: 0, duration: 0,
}, },
) => { ) => {
const nodesToFit: GraphNode[] = state.nodes.filter((node) => { const nodesToFit: GraphNode[] = []
for (const node of state.nodes) {
const isVisible = node.dimensions.width && node.dimensions.height && (options?.includeHiddenNodes || !node.hidden) const isVisible = node.dimensions.width && node.dimensions.height && (options?.includeHiddenNodes || !node.hidden)
if (options.nodes?.length) { if (isVisible) {
return isVisible && options.nodes.includes(node.id) if (!options.nodes?.length || (options.nodes?.length && options.nodes.includes(node.id))) {
nodesToFit.push(node)
}
} }
}
return isVisible
})
if (!nodesToFit.length) { if (!nodesToFit.length) {
return Promise.resolve(false) return Promise.resolve(false)
+128 -135
View File
@@ -5,6 +5,8 @@ import { until } from '@vueuse/core'
import type { import type {
Actions, Actions,
CoordinateExtent, CoordinateExtent,
Edge,
EdgeAddChange,
EdgeChange, EdgeChange,
EdgeRemoveChange, EdgeRemoveChange,
EdgeSelectionChange, EdgeSelectionChange,
@@ -13,6 +15,7 @@ import type {
GraphEdge, GraphEdge,
GraphNode, GraphNode,
Node, Node,
NodeAddChange,
NodeChange, NodeChange,
NodeDimensionChange, NodeDimensionChange,
NodePositionChange, NodePositionChange,
@@ -23,13 +26,11 @@ import type {
} from '../types' } from '../types'
import { useViewportHelper } from '../composables' import { useViewportHelper } from '../composables'
import { import {
ErrorCode,
VueFlowError,
addEdgeToStore,
applyChanges, applyChanges,
clamp, clamp,
createAdditionChange, createAdditionChange,
createEdgeRemoveChange, createEdgeRemoveChange,
createGraphEdges,
createGraphNodes, createGraphNodes,
createNodeRemoveChange, createNodeRemoveChange,
createSelectionChange, createSelectionChange,
@@ -46,7 +47,6 @@ import {
isNode, isNode,
isRect, isRect,
nodeToRect, nodeToRect,
parseEdge,
updateConnectionLookup, updateConnectionLookup,
updateEdgeAction, updateEdgeAction,
} from '../utils' } from '../utils'
@@ -192,13 +192,18 @@ export function useActions(
} }
const nodeSelectionHandler = (nodes: GraphNode[], selected: boolean) => { const nodeSelectionHandler = (nodes: GraphNode[], selected: boolean) => {
const nodeIds = nodes.map((n) => n.id) const nodeIds: string[] = []
for (const node of nodes) {
nodeIds.push(node.id)
}
let changedNodes: NodeChange[] let changedNodes: NodeChange[] = []
let changedEdges: EdgeChange[] = [] let changedEdges: EdgeChange[] = []
if (state.multiSelectionActive) { if (state.multiSelectionActive) {
changedNodes = nodeIds.map((nodeId) => createSelectionChange(nodeId, selected)) for (const nodeId of nodeIds) {
changedNodes.push(createSelectionChange(nodeId, selected))
}
} else { } else {
const selectionChanges = getSelectionChanges([...state.nodes, ...state.edges], nodeIds) const selectionChanges = getSelectionChanges([...state.nodes, ...state.edges], nodeIds)
changedNodes = selectionChanges.changedNodes changedNodes = selectionChanges.changedNodes
@@ -215,13 +220,19 @@ export function useActions(
} }
const edgeSelectionHandler = (edges: GraphEdge[], selected: boolean) => { const edgeSelectionHandler = (edges: GraphEdge[], selected: boolean) => {
const edgeIds = edges.map((e) => e.id) const edgeIds: string[] = []
for (const edge of edges) {
edgeIds.push(edge.id)
}
let changedNodes: NodeChange[] = [] let changedNodes: NodeChange[] = []
let changedEdges: EdgeChange[] let changedEdges: EdgeChange[] = []
if (state.multiSelectionActive) { if (state.multiSelectionActive) {
changedEdges = edgeIds.map((edgeId) => createSelectionChange(edgeId, selected)) for (const edgeId of edgeIds) {
changedEdges.push(createSelectionChange(edgeId, selected))
}
} else { } else {
const selectionChanges = getSelectionChanges([...state.nodes, ...state.edges], edgeIds) const selectionChanges = getSelectionChanges([...state.nodes, ...state.edges], edgeIds)
changedNodes = selectionChanges.changedNodes changedNodes = selectionChanges.changedNodes
@@ -238,14 +249,27 @@ export function useActions(
} }
const elementSelectionHandler = (elements: Elements, selected: boolean) => { const elementSelectionHandler = (elements: Elements, selected: boolean) => {
const nodeIds = elements.filter(isNode).map((n) => n.id) const nodeIds: string[] = []
const edgeIds = elements.filter(isEdge).map((e) => e.id) const edgeIds: string[] = []
let { changedNodes, changedEdges } = getSelectionChanges([...state.nodes, ...state.edges], [...nodeIds, ...edgeIds]) for (const element of elements) {
if (isNode(element)) {
nodeIds.push(element.id)
} else if (isEdge(element)) {
edgeIds.push(element.id)
}
}
const { changedNodes, changedEdges } = getSelectionChanges([...state.nodes, ...state.edges], [...nodeIds, ...edgeIds])
if (state.multiSelectionActive) { if (state.multiSelectionActive) {
changedNodes = nodeIds.map((nodeId) => createSelectionChange(nodeId, selected)) for (const nodeId of nodeIds) {
changedEdges = edgeIds.map((edgeId) => createSelectionChange(edgeId, selected)) changedNodes.push(createSelectionChange(nodeId, selected))
}
for (const edgeId of edgeIds) {
changedEdges.push(createSelectionChange(edgeId, selected))
}
} }
if (changedNodes.length) { if (changedNodes.length) {
@@ -274,9 +298,11 @@ export function useActions(
return nodeSelectionHandler(nodes, false) return nodeSelectionHandler(nodes, false)
} }
const nodeIds = nodes.map((n) => n.id) const changedNodes: NodeSelectionChange[] = []
const changedNodes = nodeIds.map((nodeId) => createSelectionChange(nodeId, false)) for (const node of nodes) {
changedNodes.push(createSelectionChange(node.id, false))
}
if (changedNodes.length) { if (changedNodes.length) {
state.hooks.nodesChange.trigger(changedNodes) state.hooks.nodesChange.trigger(changedNodes)
@@ -288,9 +314,10 @@ export function useActions(
return edgeSelectionHandler(edges, false) return edgeSelectionHandler(edges, false)
} }
const edgeIds = edges.map((e) => e.id) const changedEdges: EdgeSelectionChange[] = []
for (const edge of edges) {
const changedEdges = edgeIds.map((edgeId) => createSelectionChange(edgeId, false)) changedEdges.push(createSelectionChange(edge.id, false))
}
if (changedEdges.length) { if (changedEdges.length) {
state.hooks.edgesChange.trigger(changedEdges) state.hooks.edgesChange.trigger(changedEdges)
@@ -369,52 +396,20 @@ export function useActions(
return return
} }
const validEdges = state.isValidConnection const validEdges: GraphEdge[] = createGraphEdges(
? nextEdges.filter((edge) => nextEdges,
state.isValidConnection!(edge, { state.isValidConnection,
edges: state.edges, findNode,
nodes: state.nodes, findEdge,
sourceNode: findNode(edge.source)!, state.hooks.error.trigger,
targetNode: findNode(edge.target)!, state.defaultEdgeOptions,
}), state.nodes,
) state.edges,
: nextEdges )
updateConnectionLookup(state.connectionLookup, validEdges) updateConnectionLookup(state.connectionLookup, validEdges)
state.edges = validEdges.reduce<GraphEdge[]>((res, edge) => { state.edges = validEdges
const sourceNode = findNode(edge.source)
const targetNode = findNode(edge.target)
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
const missingTarget = !targetNode || typeof targetNode === 'undefined'
if (missingSource && missingTarget) {
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_SOURCE_TARGET_MISSING, edge.id, edge.source, edge.target))
} else {
if (missingSource) {
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_SOURCE_MISSING, edge.id, edge.source))
}
if (missingTarget) {
state.hooks.error.trigger(new VueFlowError(ErrorCode.EDGE_TARGET_MISSING, edge.id, edge.target))
}
}
if (missingSource || missingTarget) {
return res
}
const existingEdge = findEdge(edge.id)
res.push({
...parseEdge(edge, existingEdge, state.defaultEdgeOptions),
sourceNode,
targetNode,
})
return res
}, [])
} }
const setElements: Actions['setElements'] = (elements) => { const setElements: Actions['setElements'] = (elements) => {
@@ -434,7 +429,10 @@ export function useActions(
const graphNodes = createGraphNodes(nextNodes, state.nodes, findNode, state.hooks.error.trigger) const graphNodes = createGraphNodes(nextNodes, state.nodes, findNode, state.hooks.error.trigger)
const changes = graphNodes.map(createAdditionChange) const changes: NodeAddChange<any>[] = []
for (const node of graphNodes) {
changes.push(createAdditionChange(node))
}
if (changes.length) { if (changes.length) {
state.hooks.nodesChange.trigger(changes) state.hooks.nodesChange.trigger(changes)
@@ -445,35 +443,21 @@ export function useActions(
let nextEdges = params instanceof Function ? params(state.edges) : params let nextEdges = params instanceof Function ? params(state.edges) : params
nextEdges = Array.isArray(nextEdges) ? nextEdges : [nextEdges] nextEdges = Array.isArray(nextEdges) ? nextEdges : [nextEdges]
const validEdges = state.isValidConnection const validEdges = createGraphEdges(
? nextEdges.filter((edge) => { nextEdges,
return state.isValidConnection?.(edge, { state.isValidConnection,
edges: state.edges, findNode,
nodes: state.nodes, findEdge,
sourceNode: findNode(edge.source)!, state.hooks.error.trigger,
targetNode: findNode(edge.target)!, state.defaultEdgeOptions,
}) state.nodes,
}) state.edges,
: nextEdges )
const changes = validEdges.reduce((edgeChanges, connection) => { const changes: EdgeAddChange[] = []
const edge = addEdgeToStore(connection, state.edges, state.hooks.error.trigger, state.defaultEdgeOptions) for (const edge of validEdges) {
changes.push(createAdditionChange(edge))
if (edge) { }
const sourceNode = findNode(edge.source)!
const targetNode = findNode(edge.target)!
edgeChanges.push(
createAdditionChange<GraphEdge>({
...edge,
sourceNode,
targetNode,
}),
)
}
return edgeChanges
}, [] as EdgeChange[])
if (changes.length) { if (changes.length) {
state.hooks.edgesChange.trigger(changes) state.hooks.edgesChange.trigger(changes)
@@ -488,28 +472,27 @@ export function useActions(
const edgeChanges: EdgeRemoveChange[] = [] const edgeChanges: EdgeRemoveChange[] = []
function createEdgeRemovalChanges(nodes: Node[]) { function createEdgeRemovalChanges(nodes: Node[]) {
const connections = getConnectedEdges(nodes).filter((edge) => (isDef(edge.deletable) ? edge.deletable : true)) const connectedEdges = getConnectedEdges(nodes)
for (const edge of connectedEdges) {
edgeChanges.push( if (isDef(edge.deletable) ? edge.deletable : true) {
...connections.map((connection) => edgeChanges.push(createEdgeRemoveChange(edge.id, edge.source, edge.target, edge.sourceHandle, edge.targetHandle))
createEdgeRemoveChange( }
connection.id, }
connection.source,
connection.target,
connection.sourceHandle,
connection.targetHandle,
),
),
)
} }
// recursively get all children and if the child is a parent, get those children as well until all nodes have been removed that are children of the current node // recursively get all children and if the child is a parent, get those children as well until all nodes have been removed that are children of the current node
function createChildrenRemovalChanges(id: string) { function createChildrenRemovalChanges(id: string) {
const children = state.nodes.filter((n) => n.parentNode === id) const children: GraphNode[] = []
for (const node of state.nodes) {
if (node.parentNode === id) {
children.push(node)
}
}
if (children.length) { if (children.length) {
const childIds = children.map((n) => n.id) for (const child of children) {
nodeChanges.push(...childIds.map((id) => createNodeRemoveChange(id))) nodeChanges.push(createNodeRemoveChange(child.id))
}
if (removeConnectedEdges) { if (removeConnectedEdges) {
createEdgeRemovalChanges(children) createEdgeRemovalChanges(children)
@@ -684,17 +667,22 @@ export function useActions(
return [] return []
} }
return (nodes || state.nodes).filter((n) => { const intersections: GraphNode[] = []
for (const n of nodes || state.nodes) {
if (!isRect && (n.id === node!.id || !n.computedPosition)) { if (!isRect && (n.id === node!.id || !n.computedPosition)) {
return false continue
} }
const currNodeRect = nodeToRect(n) const currNodeRect = nodeToRect(n)
const overlappingArea = getOverlappingArea(currNodeRect, nodeRect) const overlappingArea = getOverlappingArea(currNodeRect, nodeRect)
const partiallyVisible = partially && overlappingArea > 0 const partiallyVisible = partially && overlappingArea > 0
return partiallyVisible || overlappingArea >= Number(nodeRect.width) * Number(nodeRect.height) if (partiallyVisible || overlappingArea >= Number(nodeRect.width) * Number(nodeRect.height)) {
}) intersections.push(n)
}
}
return intersections
} }
const isNodeIntersecting: Actions['isNodeIntersecting'] = (nodeOrRect, area, partially = true) => { const isNodeIntersecting: Actions['isNodeIntersecting'] = (nodeOrRect, area, partially = true) => {
@@ -804,32 +792,37 @@ export function useActions(
} }
const toObject: Actions['toObject'] = () => { const toObject: Actions['toObject'] = () => {
const nodes: Node[] = []
const edges: Edge[] = []
for (const node of state.nodes) {
const {
computedPosition: _,
handleBounds: __,
selected: ___,
dimensions: ____,
isParent: _____,
resizing: ______,
dragging: _______,
initialized: ________,
events: _________,
...rest
} = node
nodes.push(rest)
}
for (const edge of state.edges) {
const { selected: _, sourceNode: __, targetNode: ___, events: ____, ...rest } = edge
edges.push(rest)
}
// we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage // we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage
return JSON.parse( return JSON.parse(
JSON.stringify({ JSON.stringify({
nodes: state.nodes.map((n) => { nodes,
// omit internal properties when exporting edges,
const {
computedPosition: _,
handleBounds: __,
selected: ___,
dimensions: ____,
isParent: _____,
resizing: ______,
dragging: _______,
initialized: ________,
events: _________,
...rest
} = n
return rest
}),
edges: state.edges.map((e) => {
// omit internal properties when exporting
const { selected: _, sourceNode: __, targetNode: ___, events: ____, ...rest } = e
return rest
}),
position: [state.viewport.x, state.viewport.y], position: [state.viewport.x, state.viewport.y],
zoom: state.viewport.zoom, zoom: state.viewport.zoom,
viewport: state.viewport, viewport: state.viewport,
+88 -42
View File
@@ -58,22 +58,29 @@ export function useGetters(state: State, nodeIds: ComputedRef<string[]>, edgeIds
}) })
const getNodes: ComputedGetters['getNodes'] = computed(() => { const getNodes: ComputedGetters['getNodes'] = computed(() => {
const nodes = state.nodes.filter((n) => !n.hidden) const nodes: GraphNode[] = []
return state.onlyRenderVisibleElements for (const node of state.nodes) {
? nodes && if (!node.hidden) {
getNodesInside( nodes.push(node)
nodes, }
{ }
x: 0,
y: 0, if (state.onlyRenderVisibleElements) {
width: state.dimensions.width, return getNodesInside(
height: state.dimensions.height, nodes,
}, {
state.viewport, x: 0,
true, y: 0,
) width: state.dimensions.width,
: nodes ?? [] height: state.dimensions.height,
},
state.viewport,
true,
)
}
return nodes
}) })
const edgeHidden = (e: GraphEdge, source?: GraphNode, target?: GraphNode) => { const edgeHidden = (e: GraphEdge, source?: GraphNode, target?: GraphNode) => {
@@ -89,48 +96,87 @@ export function useGetters(state: State, nodeIds: ComputedRef<string[]>, edgeIds
} }
const getEdges: ComputedGetters['getEdges'] = computed(() => { const getEdges: ComputedGetters['getEdges'] = computed(() => {
if (!state.onlyRenderVisibleElements) { const edges: GraphEdge[] = []
return state.edges.filter((edge) => edgeHidden(edge))
for (const edge of state.edges) {
if (!edgeHidden(edge)) {
edges.push(edge)
}
} }
return state.edges.filter((e) => { if (state.onlyRenderVisibleElements) {
const source = getNode.value(e.source)! const visibleEdges: GraphEdge[] = []
const target = getNode.value(e.target)!
return ( for (const edge of edges) {
edgeHidden(e, source, target) && const source = getNode.value(edge.source)!
isEdgeVisible({ const target = getNode.value(edge.target)!
sourcePos: source.computedPosition || { x: 0, y: 0 },
targetPos: target.computedPosition || { x: 0, y: 0 }, if (
sourceWidth: source.dimensions.width, isEdgeVisible({
sourceHeight: source.dimensions.height, sourcePos: source.computedPosition || { x: 0, y: 0 },
targetWidth: target.dimensions.width, targetPos: target.computedPosition || { x: 0, y: 0 },
targetHeight: target.dimensions.height, sourceWidth: source.dimensions.width,
width: state.dimensions.width, sourceHeight: source.dimensions.height,
height: state.dimensions.height, targetWidth: target.dimensions.width,
viewport: state.viewport, targetHeight: target.dimensions.height,
}) width: state.dimensions.width,
) height: state.dimensions.height,
}) viewport: state.viewport,
})
) {
visibleEdges.push(edge)
}
}
return visibleEdges
}
return edges
}) })
const getElements: ComputedGetters['getElements'] = computed(() => [...getNodes.value, ...getEdges.value]) const getElements: ComputedGetters['getElements'] = computed(() => [...getNodes.value, ...getEdges.value])
const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => state.nodes.filter((n) => n.selected)) const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => {
const selectedNodes: GraphNode[] = []
for (const node of state.nodes) {
if (node.selected) {
selectedNodes.push(node)
}
}
const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => state.edges.filter((e) => e.selected)) return selectedNodes
})
const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => {
const selectedEdges: GraphEdge[] = []
for (const edge of state.edges) {
if (edge.selected) {
selectedEdges.push(edge)
}
}
return selectedEdges
})
const getSelectedElements: ComputedGetters['getSelectedElements'] = computed(() => [ const getSelectedElements: ComputedGetters['getSelectedElements'] = computed(() => [
...(getSelectedNodes.value ?? []), ...getSelectedNodes.value,
...(getSelectedEdges.value ?? []), ...getSelectedEdges.value,
]) ])
/** /**
* @deprecated will be removed in next major version; use `useNodesInitialized` instead * @deprecated will be removed in next major version; use `useNodesInitialized` instead
*/ */
const getNodesInitialized: ComputedGetters['getNodesInitialized'] = computed(() => const getNodesInitialized: ComputedGetters['getNodesInitialized'] = computed(() => {
getNodes.value.filter((n) => n.initialized && n.handleBounds !== undefined), const initializedNodes: GraphNode[] = []
)
for (const node of state.nodes) {
if (node.initialized && node.handleBounds !== undefined) {
initializedNodes.push(node)
}
}
return initializedNodes
})
/** /**
* @deprecated will be removed in next major version; use `useNodesInitialized` instead * @deprecated will be removed in next major version; use `useNodesInitialized` instead
+4 -2
View File
@@ -133,9 +133,11 @@ export function applyChanges<
const elementIds = elements.map((el) => el.id) const elementIds = elements.map((el) => el.id)
for (const element of elements) { for (const element of elements) {
const currentChanges = changes.filter((c) => (<any>c).id === element.id) for (const currentChange of changes) {
if ((<any>currentChange).id !== element.id) {
continue
}
for (const currentChange of currentChanges) {
switch (currentChange.type) { switch (currentChange.type) {
case 'select': case 'select':
element.selected = currentChange.selected element.selected = currentChange.selected
+30 -27
View File
@@ -34,28 +34,32 @@ export function getDragItems(
findNode: Actions['findNode'], findNode: Actions['findNode'],
nodeId?: string, nodeId?: string,
): NodeDragItem[] { ): NodeDragItem[] {
return nodes const dragItems: NodeDragItem[] = []
.filter( for (const node of nodes) {
(n) => if (
(n.selected || n.id === nodeId) && (node.selected || node.id === nodeId) &&
(!n.parentNode || !isParentSelected(n, findNode)) && (!node.parentNode || !isParentSelected(node, findNode)) &&
(n.draggable || (nodesDraggable && typeof n.draggable === 'undefined')), (node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'))
) ) {
.map((n) => dragItems.push(
markRaw({ markRaw({
id: n.id, id: node.id,
position: n.position || { x: 0, y: 0 }, position: node.position || { x: 0, y: 0 },
distance: { distance: {
x: mousePos.x - n.computedPosition?.x || 0, x: mousePos.x - node.computedPosition?.x || 0,
y: mousePos.y - n.computedPosition?.y || 0, y: mousePos.y - node.computedPosition?.y || 0,
}, },
from: n.computedPosition, from: node.computedPosition,
extent: n.extent, extent: node.extent,
parentNode: n.parentNode, parentNode: node.parentNode,
dimensions: n.dimensions, dimensions: node.dimensions,
expandParent: n.expandParent, expandParent: node.expandParent,
}), }),
) )
}
}
return dragItems
} }
export function getEventHandlerParams({ export function getEventHandlerParams({
@@ -67,15 +71,14 @@ export function getEventHandlerParams({
dragItems: NodeDragItem[] dragItems: NodeDragItem[]
findNode: Actions['findNode'] findNode: Actions['findNode']
}): [GraphNode, GraphNode[]] { }): [GraphNode, GraphNode[]] {
const extendedDragItems = dragItems.reduce((acc, dragItem) => { const extendedDragItems: GraphNode[] = []
for (const dragItem of dragItems) {
const node = findNode(dragItem.id) const node = findNode(dragItem.id)
if (node) { if (node) {
acc.push(node) extendedDragItems.push(node)
} }
}
return acc
}, [] as GraphNode[])
return [id ? extendedDragItems.find((n) => n.id === id)! : extendedDragItems[0], extendedDragItems] return [id ? extendedDragItems.find((n) => n.id === id)! : extendedDragItems[0], extendedDragItems]
} }
+81 -1
View File
@@ -1,5 +1,17 @@
import { markRaw, unref } from 'vue' import { markRaw, unref } from 'vue'
import type { Actions, Connection, ConnectionLookup, DefaultEdgeOptions, Edge, GraphEdge, GraphNode, Node, State } from '../types' import type {
Actions,
Connection,
ConnectionLookup,
DefaultEdgeOptions,
Edge,
GraphEdge,
GraphNode,
Node,
State,
ValidConnectionFunc,
VueFlowStore,
} from '../types'
import { ErrorCode, VueFlowError, connectionExists, getEdgeId, isEdge, isNode, parseEdge, parseNode } from '.' import { ErrorCode, VueFlowError, connectionExists, getEdgeId, isEdge, isNode, parseEdge, parseNode } from '.'
type NonUndefined<T> = T extends undefined ? never : T type NonUndefined<T> = T extends undefined ? never : T
@@ -195,3 +207,71 @@ export function areConnectionMapsEqual(a?: Map<string, Connection>, b?: Map<stri
return true return true
} }
/**
* @internal
*/
export function createGraphEdges(
nextEdges: (Edge | Connection)[],
isValidConnection: ValidConnectionFunc | null,
findNode: Actions['findNode'],
findEdge: Actions['findEdge'],
onError: VueFlowStore['emits']['error'],
defaultEdgeOptions: DefaultEdgeOptions | undefined,
nodes: GraphNode[],
edges: GraphEdge[],
) {
const validEdges: GraphEdge[] = []
for (const edgeOrConnection of nextEdges) {
const edge = isEdge(edgeOrConnection)
? edgeOrConnection
: addEdgeToStore(edgeOrConnection, edges, onError, defaultEdgeOptions)
if (!edge) {
continue
}
const sourceNode = findNode(edge.source)
const targetNode = findNode(edge.target)
if (!sourceNode || !targetNode) {
onError(new VueFlowError(ErrorCode.EDGE_SOURCE_TARGET_MISSING, edge.id, edge.source, edge.target))
continue
}
if (!sourceNode) {
onError(new VueFlowError(ErrorCode.EDGE_SOURCE_MISSING, edge.id, edge.source))
continue
}
if (!targetNode) {
onError(new VueFlowError(ErrorCode.EDGE_TARGET_MISSING, edge.id, edge.target))
continue
}
if (isValidConnection) {
const isValid = isValidConnection(edge, {
edges,
nodes,
sourceNode,
targetNode,
})
if (!isValid) {
onError(new VueFlowError(ErrorCode.EDGE_INVALID, edge.id))
continue
}
}
const existingEdge = findEdge(edge.id)
validEdges.push({
...parseEdge(edge, existingEdge, defaultEdgeOptions),
sourceNode,
targetNode,
})
}
return validEdges
}