feat(flow): export apply changes utilities for options api

This commit is contained in:
Braks
2022-04-04 21:42:48 +02:00
parent 4b0ac0a9b8
commit d95a83349b
4 changed files with 48 additions and 23 deletions
+7 -1
View File
@@ -20,10 +20,10 @@ export {
isNode, isNode,
isEdge, isEdge,
addEdge, addEdge,
updateEdge,
getOutgoers, getOutgoers,
getIncomers, getIncomers,
getConnectedEdges, getConnectedEdges,
updateEdge,
getTransformForBounds, getTransformForBounds,
getRectOfNodes, getRectOfNodes,
graphPosToZoomedPos, graphPosToZoomedPos,
@@ -31,6 +31,12 @@ export {
getMarkerId, getMarkerId,
} from './utils/graph' } from './utils/graph'
/**
* Intended for options API
* In composition API you can access apply utilities from `useVueFlow`
*/
export { applyChanges, applyEdgeChanges, applyNodeChanges } from './utils/changes'
export { defaultEdgeTypes, defaultNodeTypes } from './store' export { defaultEdgeTypes, defaultNodeTypes } from './store'
export { VueFlow as VueFlowInjection, NodeId as NodeIdInjection } from './context' export { VueFlow as VueFlowInjection, NodeId as NodeIdInjection } from './context'
+20 -13
View File
@@ -16,7 +16,8 @@ import {
State, State,
} from '~/types' } from '~/types'
import { import {
applyChanges, applyNodeChanges as applyNodes,
applyEdgeChanges as applyEdges,
connectionExists, connectionExists,
createPositionChange, createPositionChange,
createSelectionChange, createSelectionChange,
@@ -83,11 +84,6 @@ const updateEdgeAction = (edge: GraphEdge, newConnection: Connection, edges: Gra
return true return true
} }
const applyEdgeChangesAction = (changes: EdgeChange[], edges: GraphEdge[], getNode: Getters['getNode']) =>
applyChanges(changes, edges, getNode)
const applyNodeChangesAction = (changes: NodeChange[], nodes: GraphNode[], getNode: Getters['getNode']) =>
applyChanges(changes, nodes, getNode)
const createGraphNodes = (nodes: Node[], getNode: Getters['getNode'], currGraphNodes: GraphNode[], extent: CoordinateExtent) => { const createGraphNodes = (nodes: Node[], getNode: Getters['getNode'], currGraphNodes: GraphNode[], extent: CoordinateExtent) => {
const parentNodes: Record<string, true> = {} const parentNodes: Record<string, true> = {}
@@ -127,17 +123,18 @@ export default (state: State, getters: ComputedGetters): Actions => {
state.nodes.forEach((node) => { state.nodes.forEach((node) => {
if (node.selected) { if (node.selected) {
if (!node.parentNode) { if (!node.parentNode) {
changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, getters.getNode.value)) changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, state.nodes))
} else if (!isParentSelected(node, getters.getNode.value)) { } else if (!isParentSelected(node, getters.getNode.value)) {
changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, getters.getNode.value)) changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, state.nodes))
} }
} else if (node.id === id) { } else if (node.id === id) {
changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, getters.getNode.value)) changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, state.nodes))
} }
}) })
if (changes.length) state.hooks.nodesChange.trigger(changes) if (changes.length) state.hooks.nodesChange.trigger(changes)
} }
const updateNodeDimensions: Actions['updateNodeDimensions'] = (updates) => { const updateNodeDimensions: Actions['updateNodeDimensions'] = (updates) => {
const changes: NodeDimensionChange[] = updates.reduce<NodeDimensionChange[]>((res, update) => { const changes: NodeDimensionChange[] = updates.reduce<NodeDimensionChange[]>((res, update) => {
const node = getters.getNode.value(update.id) const node = getters.getNode.value(update.id)
@@ -167,6 +164,7 @@ export default (state: State, getters: ComputedGetters): Actions => {
if (changes.length) state.hooks.nodesChange.trigger(changes) 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)
@@ -176,6 +174,7 @@ export default (state: State, getters: ComputedGetters): Actions => {
if (changedNodes.length) state.hooks.nodesChange.trigger(changedNodes) if (changedNodes.length) state.hooks.nodesChange.trigger(changedNodes)
} }
const addSelectedEdges: Actions['addSelectedEdges'] = (edges) => { const addSelectedEdges: Actions['addSelectedEdges'] = (edges) => {
const selectedEdgesIds = edges.map((e) => e.id) const selectedEdgesIds = edges.map((e) => e.id)
@@ -185,26 +184,32 @@ export default (state: State, getters: ComputedGetters): Actions => {
if (changedEdges.length) state.hooks.edgesChange.trigger(changedEdges) if (changedEdges.length) state.hooks.edgesChange.trigger(changedEdges)
} }
const addSelectedElements: Actions['addSelectedElements'] = (elements) => { const addSelectedElements: Actions['addSelectedElements'] = (elements) => {
addSelectedNodes(elements.filter(isGraphNode)) addSelectedNodes(elements.filter(isGraphNode))
addSelectedEdges(elements.filter(isGraphEdge)) addSelectedEdges(elements.filter(isGraphEdge))
} }
const setMinZoom: Actions['setMinZoom'] = (minZoom: any) => { const setMinZoom: Actions['setMinZoom'] = (minZoom: any) => {
state.d3Zoom?.scaleExtent([minZoom, state.maxZoom]) state.d3Zoom?.scaleExtent([minZoom, state.maxZoom])
state.minZoom = minZoom state.minZoom = minZoom
} }
const setMaxZoom: Actions['setMaxZoom'] = (maxZoom: any) => { const setMaxZoom: Actions['setMaxZoom'] = (maxZoom: any) => {
state.d3Zoom?.scaleExtent([state.minZoom, maxZoom]) state.d3Zoom?.scaleExtent([state.minZoom, maxZoom])
state.maxZoom = maxZoom state.maxZoom = maxZoom
} }
const setTranslateExtent: Actions['setTranslateExtent'] = (translateExtent: any) => { const setTranslateExtent: Actions['setTranslateExtent'] = (translateExtent: any) => {
state.d3Zoom?.translateExtent(translateExtent) state.d3Zoom?.translateExtent(translateExtent)
state.translateExtent = translateExtent state.translateExtent = translateExtent
} }
const resetSelectedElements: Actions['resetSelectedElements'] = () => { const resetSelectedElements: Actions['resetSelectedElements'] = () => {
addSelectedNodes([]) addSelectedNodes([])
addSelectedEdges([]) addSelectedEdges([])
} }
const setInteractive: Actions['setInteractive'] = (isInteractive) => { const setInteractive: Actions['setInteractive'] = (isInteractive) => {
state.nodesDraggable = isInteractive state.nodesDraggable = isInteractive
state.nodesConnectable = isInteractive state.nodesConnectable = isInteractive
@@ -215,6 +220,7 @@ export default (state: State, getters: ComputedGetters): Actions => {
if (!state.initialized && !nodes.length) return if (!state.initialized && !nodes.length) return
state.nodes = createGraphNodes(nodes, getters.getNode.value, state.nodes, extent ?? state.nodeExtent) state.nodes = createGraphNodes(nodes, getters.getNode.value, state.nodes, extent ?? state.nodeExtent)
} }
const setEdges: Actions['setEdges'] = (edges) => { const setEdges: Actions['setEdges'] = (edges) => {
if (!state.initialized && !edges.length) return if (!state.initialized && !edges.length) return
state.edges = edges.map((edge) => { state.edges = edges.map((edge) => {
@@ -269,10 +275,10 @@ export default (state: State, getters: ComputedGetters): Actions => {
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection) => const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection) =>
updateEdgeAction(oldEdge, newConnection, state.edges, addEdges) updateEdgeAction(oldEdge, newConnection, state.edges, addEdges)
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) =>
applyNodeChangesAction(changes, state.nodes, getters.getNode.value) const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyNodes(changes, state.nodes)
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) =>
applyEdgeChangesAction(changes, state.edges, getters.getNode.value) const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => applyEdges(changes, state.edges)
const setState: Actions['setState'] = (opts) => { const setState: Actions['setState'] = (opts) => {
const skip = ['modelValue', 'nodes', 'edges', 'maxZoom', 'minZoom', 'translateExtent'] const skip = ['modelValue', 'nodes', 'edges', 'maxZoom', 'minZoom', 'translateExtent']
@@ -298,6 +304,7 @@ export default (state: State, getters: ComputedGetters): Actions => {
} }
if (!state.initialized) state.initialized = true if (!state.initialized) state.initialized = true
} }
return { return {
updateNodePosition, updateNodePosition,
updateNodeDimensions, updateNodeDimensions,
+10 -7
View File
@@ -12,6 +12,7 @@ import {
Getters, Getters,
CoordinateExtent, CoordinateExtent,
XYPosition, XYPosition,
GraphEdge,
} from '~/types' } from '~/types'
type CreatePositionChangeParams = { type CreatePositionChangeParams = {
@@ -21,8 +22,8 @@ type CreatePositionChangeParams = {
dragging?: boolean dragging?: boolean
} }
function handleParentExpand(updateItem: GraphNode, getNode: Getters['getNode']) { function handleParentExpand(updateItem: GraphNode, curr: GraphNode[]) {
const parent = updateItem.parentNode ? getNode(updateItem.parentNode) : undefined const parent = updateItem.parentNode ? curr.find((el) => el.id === updateItem.parentNode) : undefined
if (parent) { if (parent) {
const extendWidth = updateItem.position.x + updateItem.dimensions.width - parent.dimensions.width const extendWidth = updateItem.position.x + updateItem.dimensions.width - parent.dimensions.width
const extendHeight = updateItem.position.y + updateItem.dimensions.height - parent.dimensions.height const extendHeight = updateItem.position.y + updateItem.dimensions.height - parent.dimensions.height
@@ -94,7 +95,6 @@ export const applyChanges = <
>( >(
changes: C[], changes: C[],
elements: T[], elements: T[],
getNode: Getters['getNode'],
): T[] => { ): T[] => {
let elementIds = elements.map((el) => el.id) let elementIds = elements.map((el) => el.id)
changes.forEach((change) => { changes.forEach((change) => {
@@ -109,13 +109,13 @@ export const applyChanges = <
if (isGraphNode(el)) { if (isGraphNode(el)) {
if (typeof change.position !== 'undefined') el.position = change.position if (typeof change.position !== 'undefined') el.position = change.position
if (typeof change.dragging !== 'undefined') el.dragging = change.dragging if (typeof change.dragging !== 'undefined') el.dragging = change.dragging
if (el.expandParent && el.parentNode) handleParentExpand(el, getNode) if (el.expandParent && el.parentNode) handleParentExpand(el, elements as GraphNode[])
} }
break break
case 'dimensions': case 'dimensions':
if (isGraphNode(el)) { if (isGraphNode(el)) {
if (typeof change.dimensions !== 'undefined') el.dimensions = change.dimensions if (typeof change.dimensions !== 'undefined') el.dimensions = change.dimensions
if (el.expandParent && el.parentNode) handleParentExpand(el, getNode) if (el.expandParent && el.parentNode) handleParentExpand(el, elements as GraphNode[])
} }
break break
case 'remove': case 'remove':
@@ -128,6 +128,9 @@ export const applyChanges = <
return elements return elements
} }
export const applyEdgeChanges = (changes: EdgeChange[], edges: GraphEdge[]) => applyChanges(changes, edges)
export const applyNodeChanges = (changes: NodeChange[], nodes: GraphNode[]) => applyChanges(changes, nodes)
export const createSelectionChange = (id: string, selected: boolean): NodeSelectionChange | EdgeSelectionChange => ({ export const createSelectionChange = (id: string, selected: boolean): NodeSelectionChange | EdgeSelectionChange => ({
id, id,
type: 'select', type: 'select',
@@ -136,9 +139,9 @@ export const createSelectionChange = (id: string, selected: boolean): NodeSelect
export const createPositionChange = ( export const createPositionChange = (
{ node, diff, dragging, nodeExtent }: CreatePositionChangeParams, { node, diff, dragging, nodeExtent }: CreatePositionChangeParams,
getNode: Getters['getNode'], curr: GraphNode[],
): NodePositionChange => { ): NodePositionChange => {
const parent = node.parentNode ? getNode(node.parentNode) : undefined const parent = node.parentNode ? curr.find((el) => el.id === node.parentNode) : undefined
const change: NodePositionChange = { const change: NodePositionChange = {
id: node.id, id: node.id,
type: 'position', type: 'position',
+11 -2
View File
@@ -18,6 +18,7 @@ import {
XYPosition, XYPosition,
XYZPosition, XYZPosition,
Getters, Getters,
DefaultEdgeOptions,
} from '~/types' } from '~/types'
import { useWindow } from '~/composables' import { useWindow } from '~/composables'
@@ -139,7 +140,11 @@ export const connectionExists = (edge: Edge, elements: Elements) =>
(el.targetHandle === edge.targetHandle || (!el.targetHandle && !edge.targetHandle)), (el.targetHandle === edge.targetHandle || (!el.targetHandle && !edge.targetHandle)),
) )
export const addEdge = (edgeParams: Edge | Connection, elements: Elements) => { /**
* Intended for options API
* In composition API you can access utilities from `useVueFlow`
*/
export const addEdge = (edgeParams: Edge | Connection, elements: Elements, defaults?: DefaultEdgeOptions) => {
if (!edgeParams.source || !edgeParams.target) { if (!edgeParams.source || !edgeParams.target) {
console.warn("Can't create edge. An edge needs a source and a target.") console.warn("Can't create edge. An edge needs a source and a target.")
return elements return elements
@@ -154,12 +159,16 @@ export const addEdge = (edgeParams: Edge | Connection, elements: Elements) => {
id: getEdgeId(edgeParams), id: getEdgeId(edgeParams),
} as Edge } as Edge
} }
edge = parseEdge(edge) edge = parseEdge(edge, defaults)
if (connectionExists(edge, elements)) return elements if (connectionExists(edge, elements)) return elements
elements.push(edge) elements.push(edge)
return [...elements, edge] return [...elements, edge]
} }
/**
* Intended for options API
* In composition API you can access utilities from `useVueFlow`
*/
export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: Elements) => { export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: Elements) => {
if (!newConnection.source || !newConnection.target) { if (!newConnection.source || !newConnection.target) {
console.warn("Can't create new edge. An edge needs a source and a target.") console.warn("Can't create new edge. An edge needs a source and a target.")