refactor(nodes,edges): Add node/edge add changes

# What's changed?

* Elements are not added directly to state but parsed and emitted through change handler and then inserted to state
* Remove add element cb from apply changes
* Remove reset change (not implemented)
This commit is contained in:
Braks
2022-05-27 23:36:01 +02:00
parent 567b55b8e4
commit 1ddeffe1af
4 changed files with 67 additions and 53 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { Connection, Edge, Elements, FlowEvents, FlowInstance, FlowTransform, Node, SnapGrid } from '@braks/vue-flow'
import { Background, Controls, MarkerType, MiniMap, VueFlow, addEdge } from '@braks/vue-flow/src/index'
import { Background, Controls, MarkerType, MiniMap, VueFlow, addEdge } from '@braks/vue-flow'
const onNodeDragStart = (e: FlowEvents['nodeDragStart']) => console.log('drag start', e)
const onNodeDrag = (e: FlowEvents['nodeDrag']) => console.log('drag', e)
+20 -17
View File
@@ -18,6 +18,7 @@ import type {
import {
applyChanges,
connectionExists,
createAdditionChange,
createPositionChange,
createSelectionChange,
getDimensions,
@@ -265,20 +266,17 @@ export default (state: State, getters: ComputedGetters): Actions => {
const addNodes: Actions['addNodes'] = (nodes, extent) => {
const curr = nodes instanceof Function ? nodes(state.nodes) : nodes
state.nodes = [...state.nodes, ...createGraphNodes(curr, getters.getNode.value, state.nodes, extent ?? state.nodeExtent)]
const graphNodes = createGraphNodes(curr, getters.getNode.value, state.nodes, extent ?? state.nodeExtent)
const changes = graphNodes.map(createAdditionChange)
if (changes.length) state.hooks.nodesChange.trigger(changes)
}
const addEdges: Actions['addEdges'] = (params) => {
const curr = params instanceof Function ? params(state.edges) : params
curr.reduce<GraphEdge[]>((acc, param) => {
const edge = addEdge(
{
...param,
...state.defaultEdgeOptions,
},
state.edges,
)
const changes = curr.reduce((acc, param) => {
const edge = addEdge(param, state.edges)
if (edge) {
const sourceNode = getters.getNode.value(edge.source)!
const targetNode = getters.getNode.value(edge.target)!
@@ -289,23 +287,28 @@ export default (state: State, getters: ComputedGetters): Actions => {
if (missingTarget) console.warn(`[vueflow]: Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
if (missingTarget || missingSource) return acc
acc.push({
...edge,
sourceNode,
targetNode,
})
acc.push(
createAdditionChange<GraphEdge>({
...state.defaultEdgeOptions,
...edge,
sourceNode,
targetNode,
}),
)
}
return acc
}, state.edges)
}, [] as EdgeChange[])
if (changes.length) state.hooks.edgesChange.trigger(changes)
}
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection) =>
updateEdgeAction(oldEdge, newConnection, state.edges, addEdges)
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyChanges(changes, state.nodes, addNodes)
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyChanges(changes, state.nodes)
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => applyChanges(changes, state.edges, addEdges)
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => applyChanges(changes, state.edges)
const setState: Actions['setState'] = (options) => {
const skip = ['modelValue', 'nodes', 'edges', 'maxZoom', 'minZoom', 'translateExtent']
+10 -21
View File
@@ -1,6 +1,6 @@
import type { Dimensions, ElementData, XYPosition } from './flow'
import type { Node, NodeHandleBounds } from './node'
import type { Edge } from './edge'
import type { GraphNode, NodeHandleBounds } from './node'
import type { GraphEdge } from './edge'
export interface NodeDimensionChange {
id: string
@@ -28,32 +28,21 @@ export interface NodeRemoveChange {
}
export interface NodeAddChange<Data = ElementData> {
item: Node<Data>
item: GraphNode<Data>
type: 'add'
}
export interface NodeResetChange<Data = ElementData> {
item: Node<Data>
type: 'reset'
}
export type NodeChange =
| NodeDimensionChange
| NodePositionChange
| NodeSelectionChange
| NodeRemoveChange
| NodeAddChange
| NodeResetChange
export type NodeChange = NodeDimensionChange | NodePositionChange | NodeSelectionChange | NodeRemoveChange | NodeAddChange
export type EdgeSelectionChange = NodeSelectionChange
export type EdgeRemoveChange = NodeRemoveChange
export interface EdgeAddChange<Data = ElementData> {
item: Edge<Data>
item: GraphEdge<Data>
type: 'add'
}
export interface EdgeResetChange<Data = ElementData> {
item: Edge<Data>
type: 'reset'
}
export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange | EdgeAddChange | EdgeResetChange
export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange | EdgeAddChange
export type ElementChange = NodeChange | EdgeChange
+36 -14
View File
@@ -14,6 +14,8 @@ import type {
NodeChange,
NodePositionChange,
NodeSelectionChange,
NodeAddChange,
EdgeAddChange,
XYPosition,
} from '~/types'
@@ -24,8 +26,7 @@ interface CreatePositionChangeParams {
dragging?: boolean
}
function handleParentExpand(updateItem: GraphNode, curr: GraphNode[]) {
const parent = updateItem.parentNode ? curr.find((el) => el.id === updateItem.parentNode) : undefined
function handleParentExpand(updateItem: GraphNode, parent: GraphNode) {
if (parent) {
const extendWidth = updateItem.position.x + updateItem.dimensions.width - parent.dimensions.width
const extendHeight = updateItem.position.y + updateItem.dimensions.height - parent.dimensions.height
@@ -97,13 +98,12 @@ export const applyChanges = <
>(
changes: C[],
elements: T[],
addElement?: (els: T[]) => void,
): T[] => {
let elementIds = elements.map((el) => el.id)
changes.forEach((change) => {
if (change.type === 'add') {
if (addElement) return addElement([change.item as any])
else return elements.push(change.item as any)
const item = <T>change.item
return elements.push(item)
}
const i = elementIds.indexOf((<any>change).id)
@@ -116,13 +116,25 @@ export const applyChanges = <
if (isGraphNode(el)) {
if (typeof change.position !== 'undefined') el.position = change.position
if (typeof change.dragging !== 'undefined') el.dragging = change.dragging
if (el.expandParent && el.parentNode) handleParentExpand(el, elements as GraphNode[])
if (el.expandParent && el.parentNode) {
const parent = elements.find((parent) => parent.id === el.parentNode)
if (parent && isGraphNode(parent)) {
handleParentExpand(el, parent)
}
}
}
break
case 'dimensions':
if (isGraphNode(el)) {
if (typeof change.dimensions !== 'undefined') el.dimensions = change.dimensions
if (el.expandParent && el.parentNode) handleParentExpand(el, elements as GraphNode[])
if (el.expandParent && el.parentNode) {
const parent = elements.find((parent) => parent.id === el.parentNode)
if (parent && isGraphNode(parent)) {
handleParentExpand(el, parent)
}
}
}
break
case 'remove':
@@ -162,13 +174,12 @@ export const createPositionChange = (
let currentExtent = node.extent === 'parent' || typeof node.extent === 'undefined' ? nodeExtent : node.extent
if (node.extent === 'parent' && parent && node.dimensions.width && node.dimensions.height) {
currentExtent =
parent.dimensions.width && parent.dimensions.height
? [
[0, 0],
[parent.dimensions.width - node.dimensions.width, parent.dimensions.height - node.dimensions.height],
]
: currentExtent
if (parent.dimensions.width && parent.dimensions.height) {
currentExtent = [
[0, 0],
[parent.dimensions.width - node.dimensions.width, parent.dimensions.height - node.dimensions.height],
]
}
}
change.position = currentExtent ? clampPosition(nextPosition, currentExtent) : nextPosition
@@ -177,6 +188,17 @@ export const createPositionChange = (
return change
}
export const createAdditionChange = <
T extends GraphNode | GraphEdge = GraphNode,
C extends NodeAddChange | EdgeAddChange = T extends GraphNode ? NodeAddChange : EdgeAddChange,
>(
item: T,
): C =>
<C>{
item,
type: 'add',
}
const isParentSelected = (node: GraphNode, selectedIds: string[], getNode: Getters['getNode']): boolean => {
const parent = node.parentNode ? getNode(node.parentNode) : undefined
if (!node.parentNode || !parent) return false