fix(edges): Remove orphaned edges
# What's changed? * Remove source/targetNode properties from GraphEdge type, the source/target will be fetched with getters if necessary * Remove edges when they have no existing source or target nodes that can be found in the state * Add nodes to custom edge test
This commit is contained in:
@@ -16,8 +16,7 @@ import {
|
||||
ComputedGetters,
|
||||
} from '~/types'
|
||||
import {
|
||||
applyNodeChanges as applyNodes,
|
||||
applyEdgeChanges as applyEdges,
|
||||
applyChanges,
|
||||
connectionExists,
|
||||
createPositionChange,
|
||||
createSelectionChange,
|
||||
@@ -241,6 +240,7 @@ export default (state: State, getters: ComputedGetters): Actions => {
|
||||
const missingTarget = !targetNode || typeof targetNode === 'undefined'
|
||||
if (missingSource) console.warn(`[vueflow]: Couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
|
||||
if (missingTarget) console.warn(`[vueflow]: Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
||||
if (missingSource || missingTarget) return res
|
||||
|
||||
const storedEdge = getters.getEdge.value(edge.id)
|
||||
|
||||
@@ -249,8 +249,6 @@ export default (state: State, getters: ComputedGetters): Actions => {
|
||||
...state.defaultEdgeOptions,
|
||||
...storedEdge,
|
||||
}),
|
||||
sourceNode,
|
||||
targetNode,
|
||||
})
|
||||
|
||||
return res
|
||||
@@ -284,12 +282,11 @@ export default (state: State, getters: ComputedGetters): Actions => {
|
||||
const missingTarget = !targetNode || typeof targetNode === 'undefined'
|
||||
if (missingSource) console.warn(`[vueflow]: Couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
|
||||
if (missingTarget) console.warn(`[vueflow]: Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
||||
if (missingTarget || missingSource) return
|
||||
|
||||
state.edges.push({
|
||||
...state.defaultEdgeOptions,
|
||||
...edge,
|
||||
sourceNode,
|
||||
targetNode,
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -298,9 +295,9 @@ export default (state: State, getters: ComputedGetters): Actions => {
|
||||
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection) =>
|
||||
updateEdgeAction(oldEdge, newConnection, state.edges, addEdges)
|
||||
|
||||
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyNodes(changes, state.nodes)
|
||||
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyChanges(changes, state.nodes, addNodes)
|
||||
|
||||
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => applyEdges(changes, state.edges)
|
||||
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => applyChanges(changes, state.edges, addEdges)
|
||||
|
||||
const setState: Actions['setState'] = (options) => {
|
||||
const skip = ['modelValue', 'nodes', 'edges', 'maxZoom', 'minZoom', 'translateExtent']
|
||||
|
||||
@@ -3,6 +3,11 @@ import { State, GraphEdge, GraphNode, ComputedGetters } from '~/types'
|
||||
import { getNodesInside, isEdgeVisible } from '~/utils'
|
||||
|
||||
export default (state: State): ComputedGetters => {
|
||||
const nodeIds = computed(() => state.nodes.map((n) => n.id))
|
||||
const edgeIds = computed(() => state.edges.map((e) => e.id))
|
||||
const getNode: ComputedGetters['getNode'] = computed(() => (id: string) => state.nodes[nodeIds.value.indexOf(id)])
|
||||
const getEdge: ComputedGetters['getEdge'] = computed(() => (id: string) => state.edges[edgeIds.value.indexOf(id)])
|
||||
|
||||
const getEdgeTypes = computed(() => {
|
||||
const edgeTypes: Record<string, any> = {
|
||||
...defaultEdgeTypes,
|
||||
@@ -41,31 +46,50 @@ export default (state: State): ComputedGetters => {
|
||||
: nodes ?? []
|
||||
})
|
||||
|
||||
const edgeHidden = (e: GraphEdge) => {
|
||||
const source = getNode.value(e.source)
|
||||
const target = getNode.value(e.target)
|
||||
|
||||
if (!source || !target) {
|
||||
console.warn(`[vue-flow]: Orphaned edge ${e.id} will be removed.`)
|
||||
state.edges.splice(state.edges.indexOf(e), 1)
|
||||
return true
|
||||
}
|
||||
|
||||
return (
|
||||
!e.hidden &&
|
||||
target &&
|
||||
!target.hidden &&
|
||||
source &&
|
||||
!source.hidden &&
|
||||
source.dimensions.width &&
|
||||
source.dimensions.height &&
|
||||
target.dimensions.width &&
|
||||
target.dimensions.height
|
||||
)
|
||||
}
|
||||
const getEdges = computed<GraphEdge[]>(() => {
|
||||
if (!state.onlyRenderVisibleElements)
|
||||
return state.edges.filter((e) => !e.hidden && e.targetNode && !e.targetNode.hidden && e.sourceNode && !e.sourceNode.hidden)
|
||||
else
|
||||
return state.edges.filter(
|
||||
(e) =>
|
||||
!e.hidden &&
|
||||
e.sourceNode.dimensions.width &&
|
||||
e.sourceNode.dimensions.height &&
|
||||
e.targetNode.dimensions.width &&
|
||||
e.targetNode.dimensions.height &&
|
||||
!e.targetNode.hidden &&
|
||||
!e.sourceNode.hidden &&
|
||||
isEdgeVisible({
|
||||
sourcePos: e.sourceNode.computedPosition || { x: 0, y: 0 },
|
||||
targetPos: e.targetNode.computedPosition || { x: 0, y: 0 },
|
||||
sourceWidth: e.sourceNode.dimensions.width,
|
||||
sourceHeight: e.sourceNode.dimensions.height,
|
||||
targetWidth: e.targetNode.dimensions.width,
|
||||
targetHeight: e.targetNode.dimensions.height,
|
||||
width: state.dimensions.width,
|
||||
height: state.dimensions.height,
|
||||
viewport: state.viewport,
|
||||
}),
|
||||
if (!state.onlyRenderVisibleElements) return state.edges.filter(edgeHidden)
|
||||
|
||||
return state.edges.filter((e) => {
|
||||
const source = getNode.value(e.source)!
|
||||
const target = getNode.value(e.target)!
|
||||
|
||||
return (
|
||||
edgeHidden(e) &&
|
||||
isEdgeVisible({
|
||||
sourcePos: source.computedPosition || { x: 0, y: 0 },
|
||||
targetPos: target.computedPosition || { x: 0, y: 0 },
|
||||
sourceWidth: source.dimensions.width,
|
||||
sourceHeight: source.dimensions.height,
|
||||
targetWidth: target.dimensions.width,
|
||||
targetHeight: target.dimensions.height,
|
||||
width: state.dimensions.width,
|
||||
height: state.dimensions.height,
|
||||
viewport: state.viewport,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => state.nodes.filter((n) => n.selected))
|
||||
@@ -75,11 +99,6 @@ export default (state: State): ComputedGetters => {
|
||||
...(getSelectedEdges.value ?? []),
|
||||
])
|
||||
|
||||
const nodeIds = computed(() => state.nodes.map((n) => n.id))
|
||||
const edgeIds = computed(() => state.edges.map((e) => e.id))
|
||||
const getNode: ComputedGetters['getNode'] = computed(() => (id: string) => state.nodes[nodeIds.value.indexOf(id)])
|
||||
const getEdge: ComputedGetters['getEdge'] = computed(() => (id: string) => state.edges[edgeIds.value.indexOf(id)])
|
||||
|
||||
return {
|
||||
getNode,
|
||||
getEdge,
|
||||
|
||||
Reference in New Issue
Block a user