feat: implement workspaces
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
import useState from './state'
|
||||
import {
|
||||
Actions,
|
||||
ComputedGetters,
|
||||
Connection,
|
||||
CoordinateExtent,
|
||||
Edge,
|
||||
EdgeChange,
|
||||
Getters,
|
||||
GraphEdge,
|
||||
GraphNode,
|
||||
Node,
|
||||
NodeChange,
|
||||
NodeDimensionChange,
|
||||
NodePositionChange,
|
||||
State,
|
||||
} from '~/types'
|
||||
import {
|
||||
applyChanges,
|
||||
connectionExists,
|
||||
createPositionChange,
|
||||
createSelectionChange,
|
||||
getDimensions,
|
||||
getEdgeId,
|
||||
getHandleBounds,
|
||||
getSelectionChanges,
|
||||
isEdge,
|
||||
isGraphEdge,
|
||||
isGraphNode,
|
||||
isNode,
|
||||
isParentSelected,
|
||||
parseEdge,
|
||||
parseNode,
|
||||
} from '~/utils'
|
||||
|
||||
const isDef = <T>(val: T): val is NonNullable<T> => typeof val !== 'undefined'
|
||||
|
||||
const addEdge = (edgeParams: Edge | Connection, edges: Edge[]) => {
|
||||
if (!edgeParams.source || !edgeParams.target) {
|
||||
console.warn("Can't create edge. An edge needs a source and a target.")
|
||||
return false
|
||||
}
|
||||
|
||||
let edge
|
||||
if (isEdge(edgeParams)) {
|
||||
edge = { ...edgeParams }
|
||||
} else {
|
||||
edge = {
|
||||
...edgeParams,
|
||||
id: getEdgeId(edgeParams),
|
||||
} as Edge
|
||||
}
|
||||
edge = parseEdge(edge)
|
||||
if (connectionExists(edge, edges)) return false
|
||||
return edge
|
||||
}
|
||||
|
||||
const updateEdgeAction = (edge: GraphEdge, newConnection: Connection, edges: GraphEdge[], add: Actions['addEdges']): boolean => {
|
||||
if (!newConnection.source || !newConnection.target) {
|
||||
console.warn("Can't create new edge. An edge needs a source and a target.")
|
||||
return false
|
||||
}
|
||||
|
||||
const foundEdge = edges.find((e) => isGraphEdge(e) && e.id === edge.id)
|
||||
|
||||
if (!foundEdge) {
|
||||
console.warn(`The old edge with id=${edge.id} does not exist.`)
|
||||
return false
|
||||
}
|
||||
|
||||
edges.splice(edges.indexOf(edge), 1)
|
||||
add([
|
||||
{
|
||||
...edge,
|
||||
id: getEdgeId(newConnection),
|
||||
source: newConnection.source,
|
||||
target: newConnection.target,
|
||||
sourceHandle: newConnection.sourceHandle,
|
||||
targetHandle: newConnection.targetHandle,
|
||||
},
|
||||
])
|
||||
|
||||
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 parentNodes: Record<string, true> = {}
|
||||
|
||||
const graphNodes = nodes.map((node) => {
|
||||
const parsed = parseNode(node, extent, {
|
||||
...getNode(node.id),
|
||||
parentNode: node.parentNode,
|
||||
})
|
||||
if (node.parentNode) {
|
||||
parentNodes[node.parentNode] = true
|
||||
}
|
||||
|
||||
return parsed
|
||||
})
|
||||
|
||||
graphNodes.forEach((node) => {
|
||||
if (node.parentNode && ![...graphNodes, ...currGraphNodes].find((n) => n.id === node.parentNode)) {
|
||||
throw new Error(`Parent node ${node.parentNode} not found`)
|
||||
}
|
||||
|
||||
if (node.parentNode || parentNodes[node.id]) {
|
||||
if (parentNodes[node.id]) {
|
||||
node.isParent = true
|
||||
}
|
||||
const parent = node.parentNode ? getNode(node.parentNode) : undefined
|
||||
if (parent) parent.isParent = true
|
||||
}
|
||||
})
|
||||
|
||||
return graphNodes
|
||||
}
|
||||
|
||||
export default (state: State, getters: ComputedGetters): Actions => {
|
||||
const updateNodePosition: Actions['updateNodePosition'] = ({ id, diff = { x: 0, y: 0 }, dragging }) => {
|
||||
const changes: NodePositionChange[] = []
|
||||
|
||||
state.nodes.forEach((node) => {
|
||||
if (node.selected) {
|
||||
if (!node.parentNode) {
|
||||
changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, getters.getNode.value))
|
||||
} else if (!isParentSelected(node, getters.getNode.value)) {
|
||||
changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, getters.getNode.value))
|
||||
}
|
||||
} else if (node.id === id) {
|
||||
changes.push(createPositionChange({ node, diff, nodeExtent: state.nodeExtent, dragging }, getters.getNode.value))
|
||||
}
|
||||
})
|
||||
|
||||
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)
|
||||
)
|
||||
node.handleBounds = getHandleBounds(update.nodeElement, state.transform[2])
|
||||
|
||||
if (doUpdate) {
|
||||
node.dimensions = dimensions
|
||||
|
||||
res.push({
|
||||
id: node.id,
|
||||
type: 'dimensions',
|
||||
dimensions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}, [])
|
||||
|
||||
if (changes.length) state.hooks.nodesChange.trigger(changes)
|
||||
}
|
||||
const addSelectedNodes: Actions['addSelectedNodes'] = (nodes) => {
|
||||
const selectedNodesIds = nodes.map((n) => n.id)
|
||||
|
||||
let changedNodes: NodeChange[]
|
||||
if (state.multiSelectionActive) changedNodes = selectedNodesIds.map((nodeId) => createSelectionChange(nodeId, true))
|
||||
else changedNodes = getSelectionChanges(state.nodes, selectedNodesIds, getters.getNode.value)
|
||||
|
||||
if (changedNodes.length) state.hooks.nodesChange.trigger(changedNodes)
|
||||
}
|
||||
const addSelectedEdges: Actions['addSelectedEdges'] = (edges) => {
|
||||
const selectedEdgesIds = edges.map((e) => e.id)
|
||||
|
||||
let changedEdges: EdgeChange[]
|
||||
if (state.multiSelectionActive) changedEdges = selectedEdgesIds.map((nodeId) => createSelectionChange(nodeId, true))
|
||||
else changedEdges = getSelectionChanges(state.edges, selectedEdgesIds, getters.getNode.value)
|
||||
|
||||
if (changedEdges.length) state.hooks.edgesChange.trigger(changedEdges)
|
||||
}
|
||||
const addSelectedElements: Actions['addSelectedElements'] = (elements) => {
|
||||
addSelectedNodes(elements.filter(isGraphNode))
|
||||
addSelectedEdges(elements.filter(isGraphEdge))
|
||||
}
|
||||
const setMinZoom: Actions['setMinZoom'] = (minZoom: any) => {
|
||||
state.d3Zoom?.scaleExtent([minZoom, state.maxZoom])
|
||||
state.minZoom = minZoom
|
||||
}
|
||||
const setMaxZoom: Actions['setMaxZoom'] = (maxZoom: any) => {
|
||||
state.d3Zoom?.scaleExtent([state.minZoom, maxZoom])
|
||||
state.maxZoom = maxZoom
|
||||
}
|
||||
const setTranslateExtent: Actions['setTranslateExtent'] = (translateExtent: any) => {
|
||||
state.d3Zoom?.translateExtent(translateExtent)
|
||||
state.translateExtent = translateExtent
|
||||
}
|
||||
const resetSelectedElements: Actions['resetSelectedElements'] = () => {
|
||||
addSelectedNodes([])
|
||||
addSelectedEdges([])
|
||||
}
|
||||
const setInteractive: Actions['setInteractive'] = (isInteractive) => {
|
||||
state.nodesDraggable = isInteractive
|
||||
state.nodesConnectable = isInteractive
|
||||
state.elementsSelectable = isInteractive
|
||||
}
|
||||
|
||||
const setNodes: Actions['setNodes'] = (nodes, extent?: CoordinateExtent) => {
|
||||
if (!state.initialized && !nodes.length) return
|
||||
state.nodes = createGraphNodes(nodes, getters.getNode.value, state.nodes, extent ?? state.nodeExtent)
|
||||
}
|
||||
const setEdges: Actions['setEdges'] = (edges) => {
|
||||
if (!state.initialized && !edges.length) return
|
||||
state.edges = edges.map((edge) => {
|
||||
const sourceNode = getters.getNode.value(edge.source)!
|
||||
const targetNode = getters.getNode.value(edge.target)!
|
||||
if (!sourceNode || typeof sourceNode === 'undefined')
|
||||
console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
|
||||
if (!targetNode || typeof targetNode === 'undefined')
|
||||
console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
||||
|
||||
return {
|
||||
...parseEdge(edge, {
|
||||
...state.defaultEdgeOptions,
|
||||
...getters.getEdge.value(edge.id),
|
||||
}),
|
||||
sourceNode,
|
||||
targetNode,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const setElements: Actions['setElements'] = (elements, extent) => {
|
||||
if ((!state.initialized && !elements.length) || !elements) return
|
||||
setNodes(elements.filter(isNode), extent)
|
||||
setEdges(elements.filter(isEdge))
|
||||
}
|
||||
|
||||
const addNodes: Actions['addNodes'] = (nodes, extent) => {
|
||||
state.nodes.push(...createGraphNodes(nodes, getters.getNode.value, state.nodes, extent ?? state.nodeExtent))
|
||||
}
|
||||
|
||||
const addEdges: Actions['addEdges'] = (params) => {
|
||||
params.forEach((param) => {
|
||||
const edge = addEdge(param, state.edges)
|
||||
if (edge) {
|
||||
const sourceNode = getters.getNode.value(edge.source)!
|
||||
const targetNode = getters.getNode.value(edge.target)!
|
||||
if (!sourceNode || typeof sourceNode === 'undefined')
|
||||
console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
|
||||
if (!targetNode || typeof targetNode === 'undefined')
|
||||
console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
||||
|
||||
state.edges.push({
|
||||
...state.defaultEdgeOptions,
|
||||
...edge,
|
||||
sourceNode,
|
||||
targetNode,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection) =>
|
||||
updateEdgeAction(oldEdge, newConnection, state.edges, addEdges)
|
||||
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) =>
|
||||
applyNodeChangesAction(changes, state.nodes, getters.getNode.value)
|
||||
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) =>
|
||||
applyEdgeChangesAction(changes, state.edges, getters.getNode.value)
|
||||
|
||||
const setState: Actions['setState'] = (opts) => {
|
||||
const skip = ['modelValue', 'nodes', 'edges', 'maxZoom', 'minZoom', 'translateExtent']
|
||||
if (typeof opts.modelValue !== 'undefined') setElements(opts.modelValue, opts.nodeExtent ?? state.nodeExtent)
|
||||
if (typeof opts.nodes !== 'undefined') setNodes(opts.nodes, opts.nodeExtent ?? state.nodeExtent)
|
||||
if (typeof opts.edges !== 'undefined') setEdges(opts.edges)
|
||||
Object.keys(opts).forEach((o) => {
|
||||
const option = opts[o as keyof typeof opts]
|
||||
if (!skip.includes(o) && isDef(option)) (<any>state)[o] = option
|
||||
})
|
||||
if (!state.paneReady)
|
||||
until(() => state.d3Zoom)
|
||||
.not.toBeUndefined()
|
||||
.then(() => {
|
||||
if (typeof opts.maxZoom !== 'undefined') setMaxZoom(opts.maxZoom)
|
||||
if (typeof opts.minZoom !== 'undefined') setMinZoom(opts.minZoom)
|
||||
if (typeof opts.translateExtent !== 'undefined') setTranslateExtent(opts.translateExtent)
|
||||
})
|
||||
else {
|
||||
if (typeof opts.maxZoom !== 'undefined') setMaxZoom(opts.maxZoom)
|
||||
if (typeof opts.minZoom !== 'undefined') setMinZoom(opts.minZoom)
|
||||
if (typeof opts.translateExtent !== 'undefined') setTranslateExtent(opts.translateExtent)
|
||||
}
|
||||
if (!state.initialized) state.initialized = true
|
||||
}
|
||||
return {
|
||||
updateNodePosition,
|
||||
updateNodeDimensions,
|
||||
setElements,
|
||||
setNodes,
|
||||
setEdges,
|
||||
addNodes,
|
||||
addEdges,
|
||||
updateEdge,
|
||||
applyEdgeChanges,
|
||||
applyNodeChanges,
|
||||
addSelectedElements,
|
||||
addSelectedNodes,
|
||||
addSelectedEdges,
|
||||
setMinZoom,
|
||||
setMaxZoom,
|
||||
setTranslateExtent,
|
||||
resetSelectedElements,
|
||||
setInteractive,
|
||||
setState,
|
||||
$reset: () => {
|
||||
setState(useState())
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import { defaultEdgeTypes, defaultNodeTypes } from './state'
|
||||
import { ComputedGetters, State, GraphEdge, GraphNode } from '~/types'
|
||||
import { getNodesInside, isEdgeVisible } from '~/utils'
|
||||
|
||||
export default (state: State): ComputedGetters => {
|
||||
const getEdgeTypes = computed(() => {
|
||||
const edgeTypes: Record<string, any> = {
|
||||
...defaultEdgeTypes,
|
||||
...state.edgeTypes,
|
||||
}
|
||||
const keys = Object.keys(edgeTypes)
|
||||
state.edges?.forEach((e) => e.type && !keys.includes(e.type) && (edgeTypes[e.type] = e.type))
|
||||
return edgeTypes
|
||||
})
|
||||
|
||||
const getNodeTypes = computed(() => {
|
||||
const nodeTypes: Record<string, any> = {
|
||||
...defaultNodeTypes,
|
||||
...state.nodeTypes,
|
||||
}
|
||||
const keys = Object.keys(nodeTypes)
|
||||
state.nodes?.forEach((n) => n.type && !keys.includes(n.type) && (nodeTypes[n.type] = n.type))
|
||||
return nodeTypes
|
||||
})
|
||||
|
||||
const getNodes = computed<GraphNode[]>(() => {
|
||||
if (state.paneReady && state.dimensions.width && state.dimensions.height) {
|
||||
const nodes = state.nodes.filter((n) => !n.hidden)
|
||||
return state.onlyRenderVisibleElements
|
||||
? nodes &&
|
||||
getNodesInside(
|
||||
nodes,
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: state.dimensions.width,
|
||||
height: state.dimensions.height,
|
||||
},
|
||||
state.transform,
|
||||
true,
|
||||
)
|
||||
: nodes ?? []
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const getEdges = computed<GraphEdge[]>(() => {
|
||||
if (state.paneReady && state.dimensions.width && state.dimensions.height) {
|
||||
if (!state.onlyRenderVisibleElements)
|
||||
return state.edges.filter(
|
||||
(e) => !e.hidden && e.targetNode && !e.targetNode.hidden && e.sourceNode && !e.sourceNode.hidden,
|
||||
)
|
||||
else
|
||||
return state.edges.filter(
|
||||
(e) =>
|
||||
!e.hidden &&
|
||||
e.sourceNode.dimensions.width &&
|
||||
e.sourceNode.dimensions.height &&
|
||||
e.targetNode.dimensions.width &&
|
||||
e.targetNode.dimensions.height &&
|
||||
!e.targetNode.hidden &&
|
||||
!e.sourceNode.hidden &&
|
||||
isEdgeVisible({
|
||||
sourcePos: e.sourceNode.computedPosition || { x: 0, y: 0 },
|
||||
targetPos: e.targetNode.computedPosition || { x: 0, y: 0 },
|
||||
sourceWidth: e.sourceNode.dimensions.width,
|
||||
sourceHeight: e.sourceNode.dimensions.height,
|
||||
targetWidth: e.targetNode.dimensions.width,
|
||||
targetHeight: e.targetNode.dimensions.height,
|
||||
width: state.dimensions.width,
|
||||
height: state.dimensions.height,
|
||||
transform: state.transform,
|
||||
}),
|
||||
)
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => state.nodes.filter((n) => n.selected))
|
||||
const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => state.edges.filter((e) => e.selected))
|
||||
const getSelectedElements: ComputedGetters['getSelectedElements'] = computed(() => [
|
||||
...(getSelectedNodes.value ?? []),
|
||||
...(getSelectedEdges.value ?? []),
|
||||
])
|
||||
|
||||
const nodeIds = computed(() => state.nodes.map((n) => n.id))
|
||||
const edgeIds = computed(() => state.edges.map((e) => e.id))
|
||||
const getNode: ComputedGetters['getNode'] = computed(() => (id: string) => state.nodes[nodeIds.value.indexOf(id)])
|
||||
const getEdge: ComputedGetters['getEdge'] = computed(() => (id: string) => state.edges[edgeIds.value.indexOf(id)])
|
||||
|
||||
return {
|
||||
getNode,
|
||||
getEdge,
|
||||
getEdgeTypes,
|
||||
getNodeTypes,
|
||||
getEdges,
|
||||
getNodes,
|
||||
getSelectedElements,
|
||||
getSelectedNodes,
|
||||
getSelectedEdges,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { EmitFunc, FlowHooks, FlowEvents } from '~/types'
|
||||
|
||||
// flow event hooks
|
||||
export const createHooks = (): FlowHooks => ({
|
||||
edgesChange: createEventHook(),
|
||||
nodesChange: createEventHook(),
|
||||
nodeDoubleClick: createEventHook(),
|
||||
nodeClick: createEventHook(),
|
||||
nodeMouseEnter: createEventHook(),
|
||||
nodeMouseMove: createEventHook(),
|
||||
nodeMouseLeave: createEventHook(),
|
||||
nodeContextMenu: createEventHook(),
|
||||
nodeDragStart: createEventHook(),
|
||||
nodeDrag: createEventHook(),
|
||||
nodeDragStop: createEventHook(),
|
||||
connect: createEventHook(),
|
||||
connectStart: createEventHook(),
|
||||
connectStop: createEventHook(),
|
||||
connectEnd: createEventHook(),
|
||||
paneReady: createEventHook(),
|
||||
move: createEventHook(),
|
||||
moveStart: createEventHook(),
|
||||
moveEnd: createEventHook(),
|
||||
selectionDragStart: createEventHook(),
|
||||
selectionDrag: createEventHook(),
|
||||
selectionDragStop: createEventHook(),
|
||||
selectionContextMenu: createEventHook(),
|
||||
paneScroll: createEventHook(),
|
||||
paneClick: createEventHook(),
|
||||
paneContextMenu: createEventHook(),
|
||||
edgeContextMenu: createEventHook(),
|
||||
edgeMouseEnter: createEventHook(),
|
||||
edgeMouseMove: createEventHook(),
|
||||
edgeMouseLeave: createEventHook(),
|
||||
edgeDoubleClick: createEventHook(),
|
||||
edgeClick: createEventHook(),
|
||||
edgeUpdateStart: createEventHook(),
|
||||
edgeUpdate: createEventHook(),
|
||||
edgeUpdateEnd: createEventHook(),
|
||||
})
|
||||
|
||||
const bind = (emit: EmitFunc, hooks: FlowHooks) => {
|
||||
for (const [key, value] of Object.entries(hooks)) {
|
||||
value.on((data: FlowEvents[keyof FlowHooks]) => {
|
||||
emit(key as keyof FlowHooks, data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default (hooks: FlowHooks, emit: EmitFunc) => bind(emit, hooks)
|
||||
@@ -0,0 +1,4 @@
|
||||
export { default as useHooks, createHooks } from './hooks'
|
||||
export { default as useStore } from './store'
|
||||
export * from './actions'
|
||||
export * from './state'
|
||||
@@ -0,0 +1,131 @@
|
||||
import { createHooks } from './hooks'
|
||||
import {
|
||||
ConnectionMode,
|
||||
State,
|
||||
PanOnScrollMode,
|
||||
DefaultNodeTypes,
|
||||
DefaultEdgeTypes,
|
||||
ConnectionLineType,
|
||||
FlowOptions,
|
||||
} from '~/types'
|
||||
import {
|
||||
DefaultNode,
|
||||
InputNode,
|
||||
OutputNode,
|
||||
BezierEdge,
|
||||
SmoothStepEdge,
|
||||
StepEdge,
|
||||
StraightEdge,
|
||||
SimpleBezierEdge,
|
||||
} from '~/components'
|
||||
|
||||
export const defaultNodeTypes: DefaultNodeTypes = {
|
||||
input: InputNode,
|
||||
default: DefaultNode,
|
||||
output: OutputNode,
|
||||
}
|
||||
|
||||
export const defaultEdgeTypes: DefaultEdgeTypes = {
|
||||
default: BezierEdge,
|
||||
straight: StraightEdge,
|
||||
step: StepEdge,
|
||||
smoothstep: SmoothStepEdge,
|
||||
simplebezier: SimpleBezierEdge,
|
||||
}
|
||||
|
||||
const isDef = <T>(val: T): val is NonNullable<T> => typeof val !== 'undefined'
|
||||
|
||||
const defaultState = (): State => ({
|
||||
nodes: [],
|
||||
edges: [],
|
||||
|
||||
paneReady: false,
|
||||
initialized: false,
|
||||
instance: null,
|
||||
|
||||
dimensions: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
transform: [0, 0, 1],
|
||||
|
||||
d3Zoom: null,
|
||||
d3Selection: null,
|
||||
d3ZoomHandler: null,
|
||||
minZoom: 0.5,
|
||||
maxZoom: 2,
|
||||
translateExtent: [
|
||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||
],
|
||||
|
||||
nodeExtent: [
|
||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||
],
|
||||
preventScrolling: true,
|
||||
zoomOnScroll: true,
|
||||
zoomOnPinch: true,
|
||||
zoomOnDoubleClick: true,
|
||||
panOnScroll: false,
|
||||
panOnScrollSpeed: 0.5,
|
||||
panOnScrollMode: PanOnScrollMode.Free,
|
||||
panOnDrag: true,
|
||||
edgeUpdaterRadius: 10,
|
||||
onlyRenderVisibleElements: false,
|
||||
defaultZoom: 1,
|
||||
defaultPosition: [0, 0],
|
||||
|
||||
nodesSelectionActive: false,
|
||||
userSelectionActive: false,
|
||||
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
||||
|
||||
defaultMarkerColor: '#b1b1b7',
|
||||
connectionLineStyle: {},
|
||||
connectionLineType: ConnectionLineType.Bezier,
|
||||
connectionNodeId: null,
|
||||
connectionHandleId: null,
|
||||
connectionHandleType: null,
|
||||
connectionPosition: { x: NaN, y: NaN },
|
||||
connectionMode: ConnectionMode.Loose,
|
||||
connectionStartHandle: null,
|
||||
connectOnClick: true,
|
||||
|
||||
snapGrid: [15, 15],
|
||||
snapToGrid: false,
|
||||
|
||||
edgesUpdatable: false,
|
||||
nodesConnectable: true,
|
||||
nodesDraggable: true,
|
||||
elementsSelectable: true,
|
||||
selectNodesOnDrag: true,
|
||||
multiSelectionActive: false,
|
||||
selectionKeyCode: 'Shift',
|
||||
multiSelectionKeyCode: 'Meta',
|
||||
zoomActivationKeyCode: 'Meta',
|
||||
deleteKeyCode: 'Backspace',
|
||||
|
||||
hooks: createHooks(),
|
||||
|
||||
applyDefault: true,
|
||||
|
||||
fitViewOnInit: false,
|
||||
noDragClassName: 'nodrag',
|
||||
noWheelClassName: 'nowheel',
|
||||
noPanClassName: 'nopan',
|
||||
defaultEdgeOptions: undefined,
|
||||
|
||||
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
|
||||
})
|
||||
|
||||
export default (opts?: FlowOptions): State => {
|
||||
const state = defaultState()
|
||||
if (opts) {
|
||||
Object.keys(opts).forEach((o) => {
|
||||
const option = opts[o as keyof typeof opts]
|
||||
if (isDef(option)) (state as any)[o] = option
|
||||
})
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import useState from './state'
|
||||
import useActions from './actions'
|
||||
import useGetters from './getters'
|
||||
import { FlowHooksOn, FlowOptions, State, Store } from '~/types'
|
||||
|
||||
export default (preloadedState?: FlowOptions): Store => {
|
||||
const state: State = useState(preloadedState)
|
||||
const reactiveState = reactive(state)
|
||||
const getters = useGetters(reactiveState)
|
||||
const actions = useActions(reactiveState, getters)
|
||||
const hooksOn: FlowHooksOn = <any>{}
|
||||
Object.entries(reactiveState.hooks).forEach(([n, h]) => {
|
||||
const name = `on${n.charAt(0).toUpperCase() + n.slice(1)}`
|
||||
hooksOn[<keyof FlowHooksOn>name] = h.on as any
|
||||
})
|
||||
actions.setState(reactiveState)
|
||||
if (preloadedState) {
|
||||
if (preloadedState.modelValue) actions.setElements(preloadedState.modelValue)
|
||||
if (preloadedState.nodes) actions.setNodes(preloadedState.nodes)
|
||||
if (preloadedState.edges) actions.setEdges(preloadedState.edges)
|
||||
}
|
||||
|
||||
return {
|
||||
state: reactiveState,
|
||||
actions,
|
||||
getters,
|
||||
hooksOn,
|
||||
...toRefs(reactiveState),
|
||||
...getters,
|
||||
...actions,
|
||||
} as unknown as Store
|
||||
}
|
||||
Reference in New Issue
Block a user