feat(nodes, edges, store): Add updateNodeDimensions actions
* Returns new changes for updating node dimensions * Add expandParent prop to nodes when parents should be expanded to fit the new child in them *
This commit is contained in:
@@ -94,25 +94,15 @@ const onDragStop: DraggableEventListener = ({ event, data: { deltaX, deltaY } })
|
|||||||
store.hooks.nodeDragStop.trigger({ event, node: node.value })
|
store.hooks.nodeDragStop.trigger({ event, node: node.value })
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatePosition = (width: number, height: number) => {
|
|
||||||
const handleBounds = getHandleBounds(nodeElement.value, scale.value, id)
|
|
||||||
node.value.dimensions = {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
}
|
|
||||||
node.value.handleBounds = handleBounds
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeEmpty = (obj: Record<string, any>) => Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null))
|
const removeEmpty = (obj: Record<string, any>) => Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null))
|
||||||
|
|
||||||
store.updateNodePosition({ id: node.value.id, diff: { x: 0, y: 0 } })
|
store.updateNodePosition({ id: node.value.id, diff: { x: 0, y: 0 } })
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const dimensions = ref(getDimensions(nodeElement.value))
|
useResizeObserver(nodeElement, () => store.updateNodeDimensions([{ id: node.value.id, nodeElement: nodeElement.value, forceUpdate: true }]))
|
||||||
useResizeObserver(nodeElement, () => (dimensions.value = getDimensions(nodeElement.value)))
|
|
||||||
watch([() => node.value.type, () => node.value.sourcePosition, () => node.value.targetPosition], () =>
|
watch([() => node.value.type, () => node.value.sourcePosition, () => node.value.targetPosition], () =>
|
||||||
nextTick(() => updatePosition(dimensions.value.width, dimensions.value.height)),
|
nextTick(() => store.updateNodeDimensions([{ id: node.value.id, nodeElement: nodeElement.value }])),
|
||||||
)
|
)
|
||||||
watch(dimensions, ({ width: w, height: h }) => nextTick(() => w > 0 && h > 0 && updatePosition(w, h)), { immediate: true })
|
store.updateNodeDimensions([{ id: node.value.id, nodeElement: nodeElement.value }])
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const props = withDefaults(defineProps<FlowProps>(), {
|
|||||||
applyDefault: undefined,
|
applyDefault: undefined,
|
||||||
fitViewOnInit: undefined,
|
fitViewOnInit: undefined,
|
||||||
})
|
})
|
||||||
const emit = defineEmits([...Object.keys(createHooks()), 'update:modelValue', 'update:elements', 'update:edges', 'update:nodes'])
|
const emit = defineEmits([...Object.keys(createHooks()), 'update:modelValue', 'update:edges', 'update:nodes'])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
|
|||||||
+35
-1
@@ -12,13 +12,16 @@ import {
|
|||||||
Edge,
|
Edge,
|
||||||
Connection,
|
Connection,
|
||||||
GraphEdge,
|
GraphEdge,
|
||||||
|
NodePositionChange,
|
||||||
} from '~/types'
|
} from '~/types'
|
||||||
import {
|
import {
|
||||||
applyChanges,
|
applyChanges,
|
||||||
connectionExists,
|
connectionExists,
|
||||||
createPositionChange,
|
createPositionChange,
|
||||||
createSelectionChange,
|
createSelectionChange,
|
||||||
|
getDimensions,
|
||||||
getEdgeId,
|
getEdgeId,
|
||||||
|
getHandleBounds,
|
||||||
getSelectionChanges,
|
getSelectionChanges,
|
||||||
isEdge,
|
isEdge,
|
||||||
isGraphEdge,
|
isGraphEdge,
|
||||||
@@ -110,7 +113,7 @@ export const parseChildren = (
|
|||||||
|
|
||||||
export default (state: State, getters: ComputedGetters): Actions => {
|
export default (state: State, getters: ComputedGetters): Actions => {
|
||||||
const updateNodePosition: Actions['updateNodePosition'] = ({ id, diff = { x: 0, y: 0 }, dragging }) => {
|
const updateNodePosition: Actions['updateNodePosition'] = ({ id, diff = { x: 0, y: 0 }, dragging }) => {
|
||||||
const changes: NodeDimensionChange[] = []
|
const changes: NodePositionChange[] = []
|
||||||
|
|
||||||
state.nodes.forEach((node) => {
|
state.nodes.forEach((node) => {
|
||||||
if (node.selected) {
|
if (node.selected) {
|
||||||
@@ -126,6 +129,36 @@ export default (state: State, getters: ComputedGetters): Actions => {
|
|||||||
|
|
||||||
if (changes.length) state.hooks.nodesChange.trigger(changes)
|
if (changes.length) state.hooks.nodesChange.trigger(changes)
|
||||||
}
|
}
|
||||||
|
const updateNodeDimensions: Actions['updateNodeDimensions'] = (updates) => {
|
||||||
|
const changes: NodeDimensionChange[] = updates.reduce<NodeDimensionChange[]>((res, update) => {
|
||||||
|
const node = getters.getNode.value(update.id)
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
const dimensions = getDimensions(update.nodeElement)
|
||||||
|
const doUpdate = !!(
|
||||||
|
dimensions.width &&
|
||||||
|
dimensions.height &&
|
||||||
|
(node.dimensions.width !== dimensions.width || node.dimensions.height !== dimensions.height || update.forceUpdate)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (doUpdate) {
|
||||||
|
const handleBounds = getHandleBounds(update.nodeElement, state.transform[2])
|
||||||
|
node.dimensions = dimensions
|
||||||
|
node.handleBounds = handleBounds
|
||||||
|
|
||||||
|
res.push({
|
||||||
|
id: node.id,
|
||||||
|
type: 'dimensions',
|
||||||
|
dimensions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (changes.length) state.hooks.nodesChange.trigger(changes)
|
||||||
|
}
|
||||||
const addSelectedNodes: Actions['addSelectedNodes'] = (nodes) => {
|
const addSelectedNodes: Actions['addSelectedNodes'] = (nodes) => {
|
||||||
const selectedNodesIds = nodes.map((n) => n.id)
|
const selectedNodesIds = nodes.map((n) => n.id)
|
||||||
|
|
||||||
@@ -296,6 +329,7 @@ export default (state: State, getters: ComputedGetters): Actions => {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
updateNodePosition,
|
updateNodePosition,
|
||||||
|
updateNodeDimensions,
|
||||||
setElements,
|
setElements,
|
||||||
setNodes,
|
setNodes,
|
||||||
setEdges,
|
setEdges,
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { XYPosition, Dimensions } from './flow'
|
||||||
|
import { NodeHandleBounds, Node, GraphNode, CoordinateExtent } from './node'
|
||||||
|
import { Edge } from './edge'
|
||||||
|
|
||||||
|
export type CreatePositionChangeParams = {
|
||||||
|
node: GraphNode
|
||||||
|
nodeExtent: CoordinateExtent
|
||||||
|
diff?: XYPosition
|
||||||
|
dragging?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeDimensionChange = {
|
||||||
|
id: string
|
||||||
|
type: 'dimensions'
|
||||||
|
dimensions: Dimensions
|
||||||
|
handleBounds?: NodeHandleBounds
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodePositionChange = {
|
||||||
|
id: string
|
||||||
|
type: 'position'
|
||||||
|
position?: XYPosition
|
||||||
|
dragging?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeSelectionChange = {
|
||||||
|
id: string
|
||||||
|
type: 'select'
|
||||||
|
selected: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeRemoveChange = {
|
||||||
|
id: string
|
||||||
|
type: 'remove'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeAddChange<NodeData = any> = {
|
||||||
|
item: Node<NodeData>
|
||||||
|
type: 'add'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeResetChange<NodeData = any> = {
|
||||||
|
item: Node<NodeData>
|
||||||
|
type: 'reset'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeChange =
|
||||||
|
| NodeDimensionChange
|
||||||
|
| NodePositionChange
|
||||||
|
| NodeSelectionChange
|
||||||
|
| NodeRemoveChange
|
||||||
|
| NodeAddChange
|
||||||
|
| NodeResetChange
|
||||||
|
|
||||||
|
export type EdgeSelectionChange = NodeSelectionChange
|
||||||
|
export type EdgeRemoveChange = NodeRemoveChange
|
||||||
|
export type EdgeAddChange<EdgeData = any> = {
|
||||||
|
item: Edge<EdgeData>
|
||||||
|
type: 'add'
|
||||||
|
}
|
||||||
|
export type EdgeResetChange<EdgeData = any> = {
|
||||||
|
item: Edge<EdgeData>
|
||||||
|
type: 'reset'
|
||||||
|
}
|
||||||
|
export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange | EdgeAddChange | EdgeResetChange
|
||||||
|
export type ElementChange = NodeChange | EdgeChange
|
||||||
@@ -76,6 +76,11 @@ export interface Edge<T = any> extends Element<T> {
|
|||||||
selectable?: boolean
|
selectable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DefaultEdgeOptions = Omit<
|
||||||
|
Edge,
|
||||||
|
'id' | 'source' | 'target' | 'sourceHandle' | 'targetHandle' | 'sourceNode' | 'targetNode'
|
||||||
|
>
|
||||||
|
|
||||||
export interface EdgePositions {
|
export interface EdgePositions {
|
||||||
sourceX: number
|
sourceX: number
|
||||||
sourceY: number
|
sourceY: number
|
||||||
@@ -125,6 +130,24 @@ export interface EdgeProps<Data = any> {
|
|||||||
updatable?: boolean
|
updatable?: boolean
|
||||||
markerStart?: string
|
markerStart?: string
|
||||||
markerEnd?: string
|
markerEnd?: string
|
||||||
|
curvature?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BaseEdgeProps = Pick<
|
||||||
|
EdgeProps,
|
||||||
|
| 'label'
|
||||||
|
| 'labelStyle'
|
||||||
|
| 'labelShowBg'
|
||||||
|
| 'labelBgStyle'
|
||||||
|
| 'labelBgPadding'
|
||||||
|
| 'labelBgBorderRadius'
|
||||||
|
| 'style'
|
||||||
|
| 'markerStart'
|
||||||
|
| 'markerEnd'
|
||||||
|
> & {
|
||||||
|
centerX: number
|
||||||
|
centerY: number
|
||||||
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SmoothStepEdgeProps<Data = any> extends EdgeProps<Data> {
|
export interface SmoothStepEdgeProps<Data = any> extends EdgeProps<Data> {
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import { ConnectionLineType, ConnectionMode } from './connection'
|
|||||||
import { KeyCode, PanOnScrollMode, UseZoomPanHelper } from './zoom'
|
import { KeyCode, PanOnScrollMode, UseZoomPanHelper } from './zoom'
|
||||||
import { Actions, ComputedGetters, State, FlowStore } from './store'
|
import { Actions, ComputedGetters, State, FlowStore } from './store'
|
||||||
import { FlowHooksOn } from './hooks'
|
import { FlowHooksOn } from './hooks'
|
||||||
import { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from "~/types/components";
|
import { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
|
||||||
|
|
||||||
export type FlowElement<N = any, E = any> = GraphNode<N> | GraphEdge<E>
|
export type FlowElement<N = any, E = any> = GraphNode<N> | GraphEdge<E>
|
||||||
export type FlowElements<N = any, E = any> = FlowElement<N, E>[]
|
export type FlowElements<N = any, E = any> = FlowElement<N, E>[]
|
||||||
|
|||||||
+2
-34
@@ -2,42 +2,10 @@ import { EventHook, EventHookOn } from '@vueuse/core'
|
|||||||
import { MouseTouchEvent } from '@braks/revue-draggable'
|
import { MouseTouchEvent } from '@braks/revue-draggable'
|
||||||
import { FlowInstance, Dimensions, XYPosition } from './flow'
|
import { FlowInstance, Dimensions, XYPosition } from './flow'
|
||||||
import { GraphEdge } from './edge'
|
import { GraphEdge } from './edge'
|
||||||
import { CoordinateExtent, GraphNode, HandleBounds } from './node'
|
import { GraphNode } from './node'
|
||||||
import { Connection, OnConnectStartParams } from './connection'
|
import { Connection, OnConnectStartParams } from './connection'
|
||||||
import { FlowTransform } from './zoom'
|
import { FlowTransform } from './zoom'
|
||||||
|
import { EdgeChange, NodeChange } from './changes'
|
||||||
export type NodeDimensionChange = {
|
|
||||||
id: string
|
|
||||||
type: 'dimensions'
|
|
||||||
dimensions?: Dimensions
|
|
||||||
position?: XYPosition
|
|
||||||
handleBounds?: HandleBounds
|
|
||||||
dragging?: boolean
|
|
||||||
}
|
|
||||||
export type NodeSelectionChange = {
|
|
||||||
id: string
|
|
||||||
type: 'select'
|
|
||||||
selected: boolean
|
|
||||||
}
|
|
||||||
export type NodeRemoveChange = {
|
|
||||||
id: string
|
|
||||||
type: 'remove'
|
|
||||||
}
|
|
||||||
export type NodeChange = NodeDimensionChange | NodeSelectionChange | NodeRemoveChange
|
|
||||||
|
|
||||||
export type EdgeSelectionChange = NodeSelectionChange
|
|
||||||
export type EdgeRemoveChange = NodeRemoveChange
|
|
||||||
export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange
|
|
||||||
|
|
||||||
export type SelectionChange = EdgeSelectionChange | NodeSelectionChange
|
|
||||||
export type RemoveChange = EdgeRemoveChange | NodeRemoveChange
|
|
||||||
|
|
||||||
export type CreatePositionChangeParams = {
|
|
||||||
node: GraphNode
|
|
||||||
nodeExtent: CoordinateExtent
|
|
||||||
diff?: XYPosition
|
|
||||||
dragging?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlowEvents<N = any, E = N> {
|
export interface FlowEvents<N = any, E = N> {
|
||||||
nodesChange: NodeChange[]
|
nodesChange: NodeChange[]
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ export * from './node'
|
|||||||
export * from './zoom'
|
export * from './zoom'
|
||||||
export * from './store'
|
export * from './store'
|
||||||
export * from './hooks'
|
export * from './hooks'
|
||||||
|
export * from './changes'
|
||||||
|
|||||||
+28
-18
@@ -1,16 +1,17 @@
|
|||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { XYPosition, Position, SnapGrid, Element, XYZPosition, Dimensions } from './flow'
|
import { XYPosition, Position, SnapGrid, Element, XYZPosition, Dimensions } from './flow'
|
||||||
import { HandleElement, ValidConnectionFunc } from './components'
|
import { DefaultNodeTypes, HandleElement, ValidConnectionFunc } from './components'
|
||||||
|
|
||||||
export type CoordinateExtent = [[number, number], [number, number]]
|
export type CoordinateExtent = [[number, number], [number, number]]
|
||||||
|
|
||||||
export type HandleBounds = {
|
export type NodeHandleBounds = {
|
||||||
source?: HandleElement[]
|
source?: HandleElement[]
|
||||||
target?: HandleElement[]
|
target?: HandleElement[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Node<T = any> extends Element<T> {
|
export interface Node<T = any> extends Element<T> {
|
||||||
position: XYPosition
|
position: XYPosition
|
||||||
|
type?: keyof DefaultNodeTypes | string
|
||||||
targetPosition?: Position
|
targetPosition?: Position
|
||||||
sourcePosition?: Position
|
sourcePosition?: Position
|
||||||
draggable?: boolean
|
draggable?: boolean
|
||||||
@@ -21,29 +22,36 @@ export interface Node<T = any> extends Element<T> {
|
|||||||
isValidTargetPos?: ValidConnectionFunc
|
isValidTargetPos?: ValidConnectionFunc
|
||||||
isValidSourcePos?: ValidConnectionFunc
|
isValidSourcePos?: ValidConnectionFunc
|
||||||
extent?: 'parent' | CoordinateExtent
|
extent?: 'parent' | CoordinateExtent
|
||||||
|
expandParent?: boolean
|
||||||
children?: Node<T>[]
|
children?: Node<T>[]
|
||||||
dimensions?: Dimensions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphNode<T = any> extends Node<T> {
|
export interface GraphNode<T = any, P = any> extends Node<T> {
|
||||||
computedPosition: XYZPosition
|
computedPosition: XYZPosition
|
||||||
handleBounds: HandleBounds
|
handleBounds: NodeHandleBounds
|
||||||
dimensions: Dimensions
|
dimensions: Dimensions
|
||||||
parentNode?: GraphNode<T>
|
isParent: boolean
|
||||||
isParent?: boolean
|
selected: boolean
|
||||||
selected?: boolean
|
dragging: boolean
|
||||||
dragging?: boolean
|
parentNode?: GraphNode<P extends infer U ? U : never>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeProps<T = any> {
|
export interface NodeProps<T = any> {
|
||||||
id: string
|
id: string
|
||||||
dimensions: Dimensions
|
dimensions: Dimensions
|
||||||
handleBounds: HandleBounds
|
handleBounds: NodeHandleBounds
|
||||||
|
/** computed position is the position relative to the node's extent (i.e. parent or CoordinateExtent) */
|
||||||
computedPosition: XYZPosition
|
computedPosition: XYZPosition
|
||||||
|
/** x and y position on the graph */
|
||||||
position: XYPosition
|
position: XYPosition
|
||||||
draggable?: boolean
|
draggable: boolean
|
||||||
selectable?: boolean
|
selectable: boolean
|
||||||
connectable?: boolean
|
connectable: boolean
|
||||||
|
selected: boolean
|
||||||
|
dragging: boolean
|
||||||
|
hidden: boolean
|
||||||
|
nodeElement: HTMLDivElement
|
||||||
|
zIndex: number
|
||||||
label?:
|
label?:
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
@@ -52,17 +60,19 @@ export interface NodeProps<T = any> {
|
|||||||
}
|
}
|
||||||
class?: string
|
class?: string
|
||||||
style?: CSSProperties
|
style?: CSSProperties
|
||||||
hidden?: boolean
|
|
||||||
type?: string
|
type?: string
|
||||||
data?: T
|
data?: T
|
||||||
selected?: boolean
|
|
||||||
targetPosition?: Position
|
targetPosition?: Position
|
||||||
sourcePosition?: Position
|
sourcePosition?: Position
|
||||||
dragging?: boolean
|
|
||||||
isValidTargetPos?: ValidConnectionFunc
|
isValidTargetPos?: ValidConnectionFunc
|
||||||
isValidSourcePos?: ValidConnectionFunc
|
isValidSourcePos?: ValidConnectionFunc
|
||||||
parentNode?: any
|
parentNode?: string
|
||||||
isParent?: boolean
|
isParent?: boolean
|
||||||
children?: Node<T>[]
|
children?: Node<T>[]
|
||||||
nodeElement: HTMLDivElement
|
dragHandle?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NodeBounds = XYPosition & {
|
||||||
|
width: number | null
|
||||||
|
height: number | null
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -5,7 +5,8 @@ import { Connection, ConnectionLineType, ConnectionMode, SetConnectionId } from
|
|||||||
import { Edge, GraphEdge } from './edge'
|
import { Edge, GraphEdge } from './edge'
|
||||||
import { GraphNode, CoordinateExtent, Node } from './node'
|
import { GraphNode, CoordinateExtent, Node } from './node'
|
||||||
import { D3Selection, D3Zoom, D3ZoomHandler, KeyCode, PanOnScrollMode } from './zoom'
|
import { D3Selection, D3Zoom, D3ZoomHandler, KeyCode, PanOnScrollMode } from './zoom'
|
||||||
import { EdgeChange, FlowHooks, FlowHooksOn, NodeChange } from './hooks'
|
import { FlowHooks, FlowHooksOn } from './hooks'
|
||||||
|
import { NodeChange, EdgeChange } from './changes'
|
||||||
|
|
||||||
export interface State<N = any, E = N> extends Omit<FlowOptions<N, E>, 'id' | 'modelValue'> {
|
export interface State<N = any, E = N> extends Omit<FlowOptions<N, E>, 'id' | 'modelValue'> {
|
||||||
hooks: FlowHooks<N, E>
|
hooks: FlowHooks<N, E>
|
||||||
@@ -91,6 +92,13 @@ export interface Actions<N = any, E = N> {
|
|||||||
setInteractive: (isInteractive: boolean) => void
|
setInteractive: (isInteractive: boolean) => void
|
||||||
setState: (state: Partial<FlowOptions<N, E>>) => void
|
setState: (state: Partial<FlowOptions<N, E>>) => void
|
||||||
updateNodePosition: ({ id, diff, dragging }: { id?: string; diff?: XYPosition; dragging?: boolean }) => void
|
updateNodePosition: ({ id, diff, dragging }: { id?: string; diff?: XYPosition; dragging?: boolean }) => void
|
||||||
|
updateNodeDimensions: (
|
||||||
|
update: {
|
||||||
|
id: string
|
||||||
|
nodeElement: HTMLDivElement
|
||||||
|
forceUpdate?: boolean
|
||||||
|
}[],
|
||||||
|
) => void
|
||||||
$reset: () => void
|
$reset: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+75
-27
@@ -1,61 +1,109 @@
|
|||||||
import {
|
import {
|
||||||
CreatePositionChangeParams,
|
CreatePositionChangeParams,
|
||||||
EdgeChange,
|
EdgeChange,
|
||||||
|
EdgeSelectionChange,
|
||||||
|
ElementChange,
|
||||||
FlowElement,
|
FlowElement,
|
||||||
FlowElements,
|
FlowElements,
|
||||||
GraphNode,
|
GraphNode,
|
||||||
NodeChange,
|
NodeChange,
|
||||||
NodeDimensionChange,
|
NodeSelectionChange,
|
||||||
SelectionChange,
|
NodePositionChange,
|
||||||
} from '~/types'
|
} from '~/types'
|
||||||
import { clampPosition, isGraphNode } from '~/utils/graph'
|
import { clampPosition, isGraphNode } from '~/utils/graph'
|
||||||
|
|
||||||
|
function handleParentExpand(parent: GraphNode, updateItem: 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
|
||||||
|
|
||||||
|
if (extendWidth > 0 || extendHeight > 0 || updateItem.position.x < 0 || updateItem.position.y < 0) {
|
||||||
|
parent.style = { ...parent.style } || {}
|
||||||
|
|
||||||
|
if (extendWidth > 0) {
|
||||||
|
if (!parent.style.width) {
|
||||||
|
parent.style.width = parent.dimensions.width
|
||||||
|
}
|
||||||
|
;(<number>parent.style.width) += extendWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extendHeight > 0) {
|
||||||
|
if (!parent.style.height) {
|
||||||
|
parent.style.height = parent.dimensions.height
|
||||||
|
}
|
||||||
|
;(<number>parent.style.height) += extendHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateItem.position.x < 0) {
|
||||||
|
const xDiff = Math.abs(updateItem.position.x)
|
||||||
|
parent.position.x = parent.position.x - xDiff
|
||||||
|
;(<number>parent.style.width) += xDiff
|
||||||
|
updateItem.position.x = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateItem.position.y < 0) {
|
||||||
|
const yDiff = Math.abs(updateItem.position.y)
|
||||||
|
parent.position.y = parent.position.y - yDiff
|
||||||
|
;(<number>parent.style.height) += yDiff
|
||||||
|
updateItem.position.y = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.dimensions.width = <number>parent.style.width
|
||||||
|
parent.dimensions.height = <number>parent.style.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const applyChanges = <
|
export const applyChanges = <
|
||||||
T extends FlowElement = GraphNode,
|
T extends FlowElement = GraphNode,
|
||||||
C extends NodeChange = T extends GraphNode ? NodeChange : EdgeChange,
|
C extends ElementChange = T extends GraphNode ? NodeChange : EdgeChange,
|
||||||
>(
|
>(
|
||||||
changes: C[],
|
changes: C[],
|
||||||
elements: T[],
|
elements: T[],
|
||||||
): T[] => {
|
): T[] => {
|
||||||
let elementIds = elements.map((el) => el.id)
|
let elementIds = elements.map((el) => el.id)
|
||||||
changes.forEach((change) => {
|
changes.forEach((change) => {
|
||||||
const i = elementIds.indexOf(change.id)
|
if (change.type === 'add') return elements.push(change.item as any)
|
||||||
|
const i = elementIds.indexOf((<any>change).id)
|
||||||
const el = elements[i]
|
const el = elements[i]
|
||||||
if (el) {
|
switch (change.type) {
|
||||||
switch (change.type) {
|
case 'select':
|
||||||
case 'select':
|
el.selected = change.selected
|
||||||
el.selected = change.selected
|
break
|
||||||
break
|
case 'position':
|
||||||
case 'dimensions':
|
if (isGraphNode(el)) {
|
||||||
if (isGraphNode(el)) {
|
if (typeof change.position !== 'undefined') el.position = change.position
|
||||||
if (typeof change.dimensions !== 'undefined') el.dimensions = change.dimensions
|
if (typeof change.dragging !== 'undefined') el.dragging = change.dragging
|
||||||
if (typeof change.position !== 'undefined') el.position = change.position
|
if (el.expandParent && el.parentNode) handleParentExpand(el, el.parentNode)
|
||||||
if (typeof change.dragging !== 'undefined') el.dragging = change.dragging
|
}
|
||||||
}
|
break
|
||||||
break
|
case 'dimensions':
|
||||||
case 'remove':
|
if (isGraphNode(el)) {
|
||||||
elements.splice(i, 1)
|
if (typeof change.dimensions !== 'undefined') el.dimensions = change.dimensions
|
||||||
elementIds = elements.map((el) => el.id)
|
if (el.expandParent && el.parentNode) handleParentExpand(el, el.parentNode)
|
||||||
break
|
}
|
||||||
}
|
break
|
||||||
|
case 'remove':
|
||||||
|
elements.splice(i, 1)
|
||||||
|
elementIds = elements.map((el) => el.id)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return elements
|
return elements
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createSelectionChange = (id: string, selected: boolean): SelectionChange => ({
|
export const createSelectionChange = (id: string, selected: boolean): NodeSelectionChange | EdgeSelectionChange => ({
|
||||||
id,
|
id,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
selected,
|
selected,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const createPositionChange = ({ node, diff, dragging, nodeExtent }: CreatePositionChangeParams): NodeDimensionChange => {
|
export const createPositionChange = ({ node, diff, dragging, nodeExtent }: CreatePositionChangeParams): NodePositionChange => {
|
||||||
const change: NodeDimensionChange = {
|
const change: NodePositionChange = {
|
||||||
id: node.id,
|
id: node.id,
|
||||||
type: 'dimensions',
|
type: 'position',
|
||||||
dragging: !!dragging,
|
dragging: !!dragging,
|
||||||
handleBounds: node.handleBounds,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diff) {
|
if (diff) {
|
||||||
@@ -99,5 +147,5 @@ export const getSelectionChanges = (items: FlowElements, selectedIds: string[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}, [] as SelectionChange[])
|
}, [] as (NodeSelectionChange | EdgeSelectionChange)[])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user