diff --git a/src/components/Nodes/NodeWrapper.vue b/src/components/Nodes/NodeWrapper.vue index f18f166f..40e12667 100644 --- a/src/components/Nodes/NodeWrapper.vue +++ b/src/components/Nodes/NodeWrapper.vue @@ -42,7 +42,6 @@ const onSelectNodeHandler = (event: MouseEvent) => { store.nodesSelectionActive = false if (!node.value.selected) store.addSelectedNodes([node.value]) } - store.hooks.elementClick.trigger({ event, element: node.value }) store.hooks.nodeClick.trigger({ event, node: node.value }) } } @@ -71,7 +70,6 @@ const onDragStop: DraggableEventListener = ({ event, data: { deltaX, deltaY } }) store.addSelectedNodes([node.value]) } store.hooks.nodeClick.trigger({ event, node: node.value }) - store.hooks.elementClick.trigger({ event, element: node.value }) return } store.updateNodePosition({ id: node.value.id, diff: { x: deltaX, y: deltaY }, dragging: false }) diff --git a/src/components/NodesSelection/NodesSelection.vue b/src/components/NodesSelection/NodesSelection.vue index 342c95bd..3b70be8b 100644 --- a/src/components/NodesSelection/NodesSelection.vue +++ b/src/components/NodesSelection/NodesSelection.vue @@ -2,31 +2,27 @@ import { Draggable, DraggableEventListener } from '@braks/revue-draggable' import { useVueFlow } from '../../composables' import { getRectOfNodes } from '../../utils' -import { GraphNode } from '../../types' -interface Props { - nodes: GraphNode[] -} const { store } = useVueFlow() -const props = defineProps() -const selectedNodesBBox = computed(() => getRectOfNodes(props.nodes)) +const selectedNodesBBox = computed(() => getRectOfNodes(store.getSelectedNodes)) const innerStyle = computed(() => ({ width: `${selectedNodesBBox.value.width}px`, height: `${selectedNodesBBox.value.height}px`, top: `${selectedNodesBBox.value.y}px`, left: `${selectedNodesBBox.value.x}px`, })) -watch(selectedNodesBBox, (v) => (store.selectedNodesBbox = v)) -const onStart: DraggableEventListener = ({ event }) => store.hooks.selectionDragStart.trigger({ event, nodes: props.nodes }) +watch(selectedNodesBBox, (v) => nextTick(() => (store.selectedNodesBbox = v))) +const onStart: DraggableEventListener = ({ event }) => + store.hooks.selectionDragStart.trigger({ event, nodes: store.getSelectedNodes }) const onDrag: DraggableEventListener = ({ event, data: { deltaX, deltaY } }) => { - store.hooks.selectionDrag.trigger({ event, nodes: props.nodes }) + store.hooks.selectionDrag.trigger({ event, nodes: store.getSelectedNodes }) store.updateNodePosition({ diff: { x: deltaX, y: deltaY }, dragging: true }) } const onStop: DraggableEventListener = ({ event }) => { - store.hooks.selectionDragStop.trigger({ event, nodes: props.nodes }) - props.nodes.forEach((node) => (node.dragging = false)) + store.hooks.selectionDragStop.trigger({ event, nodes: store.getSelectedNodes }) + store.getSelectedNodes.forEach((node) => (node.dragging = false)) } -const onContextMenu = (event: MouseEvent) => store.hooks.selectionContextMenu.trigger({ event, nodes: props.nodes }) +const onContextMenu = (event: MouseEvent) => store.hooks.selectionContextMenu.trigger({ event, nodes: store.getSelectedNodes }) const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`) diff --git a/src/composables/index.ts b/src/composables/index.ts index 3b68fd24..4ff5c57e 100644 --- a/src/composables/index.ts +++ b/src/composables/index.ts @@ -2,4 +2,4 @@ export { default as useHandle } from './useHandle' export { default as useKeyPress } from './useKeyPress' export { default as useZoomPanHelper } from './useZoomPanHelper' export { default as useWindow } from './useWindow' -export { default as useVueFlow, initFlow } from './useVueFlow' +export { default as useVueFlow } from './useVueFlow' diff --git a/src/composables/useVueFlow.ts b/src/composables/useVueFlow.ts index cc316a77..bd56f013 100644 --- a/src/composables/useVueFlow.ts +++ b/src/composables/useVueFlow.ts @@ -1,8 +1,6 @@ import { EdgeChange, - EmitFunc, FlowOptions, - FlowStore, NodeChange, UseVueFlow, FlowElements, @@ -10,59 +8,45 @@ import { GraphNode, GraphEdge, SelectionChange, + NodeDimensionChange, + CreatePositionChangeParams, } from '~/types' -import { useStore, useHooks } from '~/store' -import { isGraphNode } from '~/utils' +import { useStore } from '~/store' +import { clampPosition, isGraphNode } from '~/utils' -const applyChanges = (changes: NodeChange[] | EdgeChange[], elements: FlowElements): FlowElements => { - const initElements: FlowElements = [] - - return elements.reduce((res: FlowElements, item: FlowElement) => { - const currentChange = changes.find((c) => c.id === item.id) - - if (currentChange) { - switch (currentChange.type) { - case 'select': { - res.push({ ...item, selected: currentChange.selected }) - return res - } - case 'dimensions': { - const updateItem = { ...item } - - if (isGraphNode(updateItem)) { - if (typeof currentChange.dimensions !== 'undefined') { - updateItem.dimensions.width = currentChange.dimensions.width - updateItem.dimensions.height = currentChange.dimensions.height - } - - if (typeof currentChange.position !== 'undefined') { - updateItem.position = currentChange.position - } - - if (typeof currentChange.dragging !== 'undefined') { - updateItem.dragging = currentChange.dragging - } +const applyChanges = ( + 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 } - - res.push(updateItem) - return res - } - case 'remove': { - return res - } + break + case 'remove': + elements.splice(i, 1) + elementIds = elements.map((el) => el.id) + break } } + }) - res.push(item) - return res - }, initElements) + return elements } -export const applyNodeChanges = (changes: NodeChange[], nodes: GraphNode[]): GraphNode[] => - applyChanges(changes, nodes) - -export const applyEdgeChanges = (changes: EdgeChange[], edges: GraphEdge[]): GraphEdge[] => - applyChanges(changes, edges) +const applyNodeChanges = (changes: NodeChange[], nodes: GraphNode[]) => applyChanges(changes, nodes) +const applyEdgeChanges = (changes: EdgeChange[], edges: GraphEdge[]) => applyChanges(changes, edges) export const createSelectionChange = (id: string, selected: boolean): SelectionChange => ({ id, @@ -70,6 +54,37 @@ export const createSelectionChange = (id: string, selected: boolean): SelectionC 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 = @@ -87,12 +102,6 @@ export const getSelectionChanges = (items: FlowElements, selectedIds: string[]) }, [] as SelectionChange[]) } -export const initFlow = (emit: EmitFunc, id?: string): FlowStore => { - const store = useStore({ id }) - useHooks(store, emit) - return store -} - export default (options?: FlowOptions): UseVueFlow => { const store = useStore(options) return { diff --git a/src/container/SelectionPane/SelectionPane.vue b/src/container/SelectionPane/SelectionPane.vue index 6e79261c..bb9e816e 100644 --- a/src/container/SelectionPane/SelectionPane.vue +++ b/src/container/SelectionPane/SelectionPane.vue @@ -33,6 +33,7 @@ onMounted(() => { store.hooks.nodesChange.trigger(nodeChanges) store.hooks.edgesChange.trigger(edgeChanges) store.nodesSelectionActive = false + store.resetSelectedElements() } }) @@ -56,9 +57,8 @@ export default {