feat(store): add addSelectedNodes, addSelectedEdges, updateNodePosition actions
Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
+73
-81
@@ -1,64 +1,75 @@
|
|||||||
import { CoordinateExtent, FlowActions, FlowGetters, FlowState, GraphNode, Node } from '~/types'
|
import { CoordinateExtent, FlowActions, FlowGetters, FlowState, GraphNode, Node, XYPosition } from '~/types'
|
||||||
import { getConnectedEdges, getNodesInside, getRectOfNodes, isEdge, isNode, parseEdge, parseNode } from '~/utils'
|
import { clampPosition, isEdge, isGraphEdge, isGraphNode, isNode, isParentSelected, parseEdge, parseNode } from '~/utils'
|
||||||
|
|
||||||
|
const getParent = (root: Node[], id: string): GraphNode | undefined => {
|
||||||
|
let node
|
||||||
|
root.some((n) => {
|
||||||
|
if (n.id === id) return (node = n)
|
||||||
|
if (n.children) return (node = getParent(n.children, id))
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatePosition = (node: GraphNode, { x, y }: XYPosition = { x: 0, y: 0 }, extent: CoordinateExtent, dragging?: boolean) => {
|
||||||
|
let position = {
|
||||||
|
x: node.position.x + x,
|
||||||
|
y: node.position.y + y,
|
||||||
|
z: node.computedPosition.z,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.extent === 'parent' && node.parentNode && node.dimensions.width && node.dimensions.height) {
|
||||||
|
const parent = node.parentNode
|
||||||
|
extent =
|
||||||
|
parent.dimensions.width && parent.dimensions.height
|
||||||
|
? [
|
||||||
|
[0, 0],
|
||||||
|
[parent.dimensions.width - node.dimensions.width, parent.dimensions.height - node.dimensions.height],
|
||||||
|
]
|
||||||
|
: extent
|
||||||
|
}
|
||||||
|
node.dragging = dragging
|
||||||
|
const clamped = clampPosition(position, extent)
|
||||||
|
position = { ...position, ...clamped }
|
||||||
|
node.computedPosition = position
|
||||||
|
node.position = position
|
||||||
|
}
|
||||||
|
|
||||||
export default (state: FlowState, getters: FlowGetters): FlowActions => {
|
export default (state: FlowState, getters: FlowGetters): FlowActions => {
|
||||||
const setUserSelection: FlowActions['setUserSelection'] = (mousePos) => {
|
const updateNodePosition: FlowActions['updateNodePosition'] = ({ id, diff = { x: 0, y: 0 }, dragging }) => {
|
||||||
state.selectionActive = true
|
state.nodes.forEach((node) => {
|
||||||
state.userSelectionRect = {
|
if (node.selected) {
|
||||||
width: 0,
|
if (!node.parentNode) {
|
||||||
height: 0,
|
updatePosition(node, diff, state.nodeExtent, dragging)
|
||||||
startX: mousePos.x,
|
} else if (!isParentSelected(node)) {
|
||||||
startY: mousePos.y,
|
updatePosition(node, diff, state.nodeExtent, dragging)
|
||||||
x: mousePos.x,
|
}
|
||||||
y: mousePos.y,
|
} else if (node.id === id) {
|
||||||
draw: true,
|
updatePosition(node, diff, state.nodeExtent, dragging)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const updateUserSelection: FlowActions['updateUserSelection'] = (mousePos) => {
|
const addSelectedNodes: FlowActions['addSelectedNodes'] = (nodes) => {
|
||||||
const startX = state.userSelectionRect.startX
|
const selectedElementsUpdated = nodes.filter((el) => !state.selectedNodes.some((e) => el.id === e.id)).length
|
||||||
const startY = state.userSelectionRect.startY
|
const selectedNodes = !nodes.length || selectedElementsUpdated ? nodes : state.selectedNodes
|
||||||
|
const selectedNodesIds = selectedNodes.map((n) => n.id)
|
||||||
state.selectedElements?.forEach((el) => isNode(el) && (el.selected = undefined))
|
state.nodes.forEach(
|
||||||
const nextUserSelectRect: FlowState['userSelectionRect'] = {
|
(n) => (n.selected = selectedNodesIds.includes(n.id) || (n.parentNode && selectedNodesIds.includes(n.parentNode?.id))),
|
||||||
...state.userSelectionRect,
|
)
|
||||||
x: mousePos.x < startX ? mousePos.x : state.userSelectionRect.x,
|
state.selectedNodes = selectedNodes
|
||||||
y: mousePos.y < startY ? mousePos.y : state.userSelectionRect.y,
|
if (selectedElementsUpdated) state.hooks.selectionChange.trigger({ nodes })
|
||||||
width: Math.abs(mousePos.x - startX),
|
|
||||||
height: Math.abs(mousePos.y - startY),
|
|
||||||
}
|
|
||||||
const selectedNodes = getNodesInside(getters.getNodes.value, state.userSelectionRect, state.transform)
|
|
||||||
const selectedEdges = getConnectedEdges(selectedNodes, getters.getEdges.value)
|
|
||||||
|
|
||||||
const nextSelectedElements = [...selectedNodes, ...selectedEdges]
|
|
||||||
nextSelectedElements.forEach((el) => isNode(el) && (el.selected = true))
|
|
||||||
state.userSelectionRect = nextUserSelectRect
|
|
||||||
state.selectedElements = nextSelectedElements
|
|
||||||
}
|
}
|
||||||
const unsetUserSelection: FlowActions['unsetUserSelection'] = () => {
|
const addSelectedEdges: FlowActions['addSelectedEdges'] = (edges) => {
|
||||||
state.selectionActive = false
|
const selectedElementsUpdated = edges.filter((el) => !state.selectedEdges.some((e) => el.id === e.id)).length
|
||||||
state.userSelectionRect.draw = false
|
const selectedEdges = !edges.length || selectedElementsUpdated ? edges : state.selectedEdges
|
||||||
|
const selectedEdgesIds = selectedEdges.map((e) => e.id)
|
||||||
if (!getters.getSelectedNodes || getters.getSelectedNodes.value.length === 0) {
|
state.edges.forEach((e) => (e.selected = selectedEdgesIds.includes(e.id)))
|
||||||
state.selectedElements = undefined
|
state.selectedEdges = selectedEdges
|
||||||
state.hooks.selectionChange.trigger(undefined)
|
if (selectedElementsUpdated) state.hooks.selectionChange.trigger({ edges })
|
||||||
state.nodesSelectionActive = false
|
|
||||||
} else {
|
|
||||||
state.selectedNodesBbox = getRectOfNodes(getters.getSelectedNodes.value)
|
|
||||||
state.nodesSelectionActive = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const addSelectedElements: FlowActions['addSelectedElements'] = (elements: any) => {
|
const addSelectedElements: FlowActions['addSelectedElements'] = (elements) => {
|
||||||
const selectedElementsArr = Array.isArray(elements) ? elements : [elements]
|
addSelectedNodes(elements.filter(isGraphNode))
|
||||||
const selectedElementsUpdated = selectedElementsArr.filter(
|
addSelectedEdges(elements.filter(isGraphEdge))
|
||||||
(el) => !state.selectedElements?.some((e) => el.id === e.id),
|
|
||||||
).length
|
|
||||||
state.selectedElements = selectedElementsUpdated ? selectedElementsArr : state.selectedElements
|
|
||||||
if (selectedElementsUpdated) state.hooks.selectionChange.trigger(selectedElementsArr)
|
|
||||||
}
|
|
||||||
const initD3Zoom: FlowActions['initD3Zoom'] = ({ d3ZoomHandler, d3Zoom, d3Selection }) => {
|
|
||||||
state.d3Zoom = d3Zoom
|
|
||||||
state.d3Selection = d3Selection
|
|
||||||
state.d3ZoomHandler = d3ZoomHandler
|
|
||||||
}
|
}
|
||||||
const setMinZoom: FlowActions['setMinZoom'] = (minZoom: any) => {
|
const setMinZoom: FlowActions['setMinZoom'] = (minZoom: any) => {
|
||||||
state.d3Zoom?.scaleExtent([minZoom, state.maxZoom])
|
state.d3Zoom?.scaleExtent([minZoom, state.maxZoom])
|
||||||
@@ -73,13 +84,8 @@ export default (state: FlowState, getters: FlowGetters): FlowActions => {
|
|||||||
state.translateExtent = translateExtent
|
state.translateExtent = translateExtent
|
||||||
}
|
}
|
||||||
const resetSelectedElements: FlowActions['resetSelectedElements'] = () => {
|
const resetSelectedElements: FlowActions['resetSelectedElements'] = () => {
|
||||||
state.selectedElements = undefined
|
addSelectedNodes([])
|
||||||
}
|
addSelectedEdges([])
|
||||||
const unsetNodesSelection: FlowActions['unsetNodesSelection'] = () => {
|
|
||||||
state.nodesSelectionActive = false
|
|
||||||
}
|
|
||||||
const updateSize: FlowActions['updateSize'] = (size) => {
|
|
||||||
state.dimensions = size
|
|
||||||
}
|
}
|
||||||
const setConnectionNodeId: FlowActions['setConnectionNodeId'] = ({
|
const setConnectionNodeId: FlowActions['setConnectionNodeId'] = ({
|
||||||
connectionHandleId,
|
connectionHandleId,
|
||||||
@@ -96,16 +102,6 @@ export default (state: FlowState, getters: FlowGetters): FlowActions => {
|
|||||||
state.elementsSelectable = isInteractive
|
state.elementsSelectable = isInteractive
|
||||||
}
|
}
|
||||||
|
|
||||||
const getParent = (root: Node[], id: string): GraphNode | undefined => {
|
|
||||||
let node
|
|
||||||
root.some((n) => {
|
|
||||||
if (n.id === id) return (node = n)
|
|
||||||
if (n.children) return (node = getParent(n.children, id))
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseChildren = (n: Node, p: GraphNode | undefined, arr: GraphNode[], extent: CoordinateExtent) => {
|
const parseChildren = (n: Node, p: GraphNode | undefined, arr: GraphNode[], extent: CoordinateExtent) => {
|
||||||
const parent = typeof p === 'undefined' || typeof p !== 'object' ? getParent(arr, n.id) : p
|
const parent = typeof p === 'undefined' || typeof p !== 'object' ? getParent(arr, n.id) : p
|
||||||
const parsed = parseNode(n, extent, {
|
const parsed = parseNode(n, extent, {
|
||||||
@@ -173,8 +169,7 @@ export default (state: FlowState, getters: FlowGetters): FlowActions => {
|
|||||||
if (typeof opts.edgesUpdatable !== 'undefined') state.edgesUpdatable = opts.edgesUpdatable
|
if (typeof opts.edgesUpdatable !== 'undefined') state.edgesUpdatable = opts.edgesUpdatable
|
||||||
if (typeof opts.nodesConnectable !== 'undefined') state.nodesConnectable = opts.nodesConnectable
|
if (typeof opts.nodesConnectable !== 'undefined') state.nodesConnectable = opts.nodesConnectable
|
||||||
if (typeof opts.nodesDraggable !== 'undefined') state.nodesDraggable = opts.nodesDraggable
|
if (typeof opts.nodesDraggable !== 'undefined') state.nodesDraggable = opts.nodesDraggable
|
||||||
if (typeof opts.arrowHeadColor !== 'undefined') state.arrowHeadColor = opts.arrowHeadColor
|
if (typeof opts.defaultMarkerColor !== 'undefined') state.defaultMarkerColor = opts.defaultMarkerColor
|
||||||
if (typeof opts.markerEndId !== 'undefined') state.markerEndId = opts.markerEndId
|
|
||||||
if (typeof opts.deleteKeyCode !== 'undefined') state.deleteKeyCode = opts.deleteKeyCode
|
if (typeof opts.deleteKeyCode !== 'undefined') state.deleteKeyCode = opts.deleteKeyCode
|
||||||
if (typeof opts.selectionKeyCode !== 'undefined') state.selectionKeyCode = opts.selectionKeyCode
|
if (typeof opts.selectionKeyCode !== 'undefined') state.selectionKeyCode = opts.selectionKeyCode
|
||||||
if (typeof opts.zoomActivationKeyCode !== 'undefined') state.zoomActivationKeyCode = opts.zoomActivationKeyCode
|
if (typeof opts.zoomActivationKeyCode !== 'undefined') state.zoomActivationKeyCode = opts.zoomActivationKeyCode
|
||||||
@@ -197,20 +192,17 @@ export default (state: FlowState, getters: FlowGetters): FlowActions => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
updateNodePosition,
|
||||||
setElements,
|
setElements,
|
||||||
setNodes,
|
setNodes,
|
||||||
setEdges,
|
setEdges,
|
||||||
setUserSelection,
|
|
||||||
updateUserSelection,
|
|
||||||
unsetUserSelection,
|
|
||||||
addSelectedElements,
|
addSelectedElements,
|
||||||
initD3Zoom,
|
addSelectedNodes,
|
||||||
|
addSelectedEdges,
|
||||||
setMinZoom,
|
setMinZoom,
|
||||||
setMaxZoom,
|
setMaxZoom,
|
||||||
setTranslateExtent,
|
setTranslateExtent,
|
||||||
resetSelectedElements,
|
resetSelectedElements,
|
||||||
unsetNodesSelection,
|
|
||||||
updateSize,
|
|
||||||
setConnectionNodeId,
|
setConnectionNodeId,
|
||||||
setInteractive,
|
setInteractive,
|
||||||
setState,
|
setState,
|
||||||
|
|||||||
Reference in New Issue
Block a user