Files
vue-flow/src/utils/changes.ts
T

100 lines
2.9 KiB
TypeScript

import {
CreatePositionChangeParams,
EdgeChange,
FlowElement,
FlowElements,
GraphNode,
NodeChange,
NodeDimensionChange,
SelectionChange,
} from '~/types'
import { clampPosition, isGraphNode } from '~/utils/graph'
export const applyChanges = <
T extends FlowElement = GraphNode,
C extends NodeChange = T extends GraphNode ? NodeChange : EdgeChange,
>(
changes: C[],
elements: T[],
): T[] => {
let elementIds = elements.map((el) => el.id)
changes.forEach((change) => {
const i = elementIds.indexOf(change.id)
const el = elements[i]
if (el) {
switch (change.type) {
case 'select':
el.selected = change.selected
break
case 'dimensions':
if (isGraphNode(el)) {
if (typeof change.dimensions !== 'undefined') el.dimensions = change.dimensions
if (typeof change.position !== 'undefined') el.position = change.position
if (typeof change.dragging !== 'undefined') el.dragging = change.dragging
}
break
case 'remove':
elements.splice(i, 1)
elementIds = elements.map((el) => el.id)
break
}
}
})
return elements
}
export const createSelectionChange = (id: string, selected: boolean): SelectionChange => ({
id,
type: 'select',
selected,
})
export const createPositionChange = ({ node, diff, dragging, nodeExtent }: CreatePositionChangeParams): NodeDimensionChange => {
const change: NodeDimensionChange = {
id: node.id,
type: 'dimensions',
dragging: !!dragging,
handleBounds: node.handleBounds,
}
if (diff) {
const nextPosition = { x: node.position.x + diff.x, y: node.position.y + diff.y }
let currentExtent = nodeExtent || node.extent
if (node.extent === 'parent' && node.parentNode && node.dimensions.width && node.dimensions.height) {
currentExtent =
node.parentNode?.dimensions.width && node.parentNode?.dimensions.height
? [
[0, 0],
[
node.parentNode.dimensions.width - node.dimensions.width,
node.parentNode.dimensions.height - node.dimensions.height,
],
]
: currentExtent
}
change.position = currentExtent ? clampPosition(nextPosition, currentExtent) : nextPosition
}
return change
}
export const getSelectionChanges = (items: FlowElements, selectedIds: string[]) => {
return items.reduce((res, item) => {
const willBeSelected =
selectedIds.includes(item.id) || (isGraphNode(item) && item.parentNode && selectedIds.includes(item.parentNode?.id))
if (!item.selected && willBeSelected) {
item.selected = true
res.push(createSelectionChange(item.id, true))
} else if (item.selected && !willBeSelected) {
item.selected = false
res.push(createSelectionChange(item.id, false))
}
return res
}, [] as SelectionChange[])
}