100 lines
2.9 KiB
TypeScript
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[])
|
|
}
|