update!: graphnode and node typing
* graphnode is a node containing internal Vue Flow data * move util files to util directory * move flow actions type into store file * rename panel type file to zoom * rename types file to flow * Rename Node to NodeWrapper * Rename Edge to EdgeWrapper Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -35,7 +35,7 @@ const onLoad = (flowInstance: FlowInstance) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const updatePos = () => {
|
const updatePos = () => {
|
||||||
elements.value = elements.value.map((el: FlowElement) => {
|
elements.value = elements.value.map((el) => {
|
||||||
if (isNode(el)) {
|
if (isNode(el)) {
|
||||||
el.position = {
|
el.position = {
|
||||||
x: Math.random() * 400,
|
x: Math.random() * 400,
|
||||||
@@ -50,7 +50,7 @@ const logToObject = () => console.log(rfInstance.value?.toObject())
|
|||||||
const resetTransform = () => rfInstance.value?.setTransform({ x: 0, y: 0, zoom: 1 })
|
const resetTransform = () => rfInstance.value?.setTransform({ x: 0, y: 0, zoom: 1 })
|
||||||
|
|
||||||
const toggleclasss = () => {
|
const toggleclasss = () => {
|
||||||
elements.value = elements.value.map((el: FlowElement) => {
|
elements.value = elements.value.map((el) => {
|
||||||
if (isNode(el)) el.class = el.class === 'light' ? 'dark' : 'light'
|
if (isNode(el)) el.class = el.class === 'light' ? 'dark' : 'light'
|
||||||
return el
|
return el
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getEdgeCenter, getBezierPath, getMarkerEnd, ArrowHeadType, Edge, ElementId, Position, useVueFlow } from '~/index'
|
import { getEdgeCenter, getBezierPath, getMarkerEnd, ArrowHeadType, ElementId, Position, useVueFlow, EdgeProps } from '~/index'
|
||||||
|
|
||||||
interface CustomEdgeProps<T = any> extends Edge<T> {
|
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||||
id: ElementId
|
id: ElementId
|
||||||
sourceX: number
|
sourceX: number
|
||||||
sourceY: number
|
sourceY: number
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ const nodeClassNameFunc = props.nodeClassName instanceof Function ? props.nodeCl
|
|||||||
|
|
||||||
const shapeRendering: ShapeRendering = typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'
|
const shapeRendering: ShapeRendering = typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'
|
||||||
|
|
||||||
const nodes = computed(() => store.nodes.filter((node) => !node.isHidden))
|
const bb = computed(() => getRectOfNodes(store.getNodes))
|
||||||
const bb = computed(() => getRectOfNodes(nodes.value))
|
|
||||||
const viewBB = computed(() => ({
|
const viewBB = computed(() => ({
|
||||||
x: -store.transform[0] / store.transform[2],
|
x: -store.transform[0] / store.transform[2],
|
||||||
y: -store.transform[1] / store.transform[2],
|
y: -store.transform[1] / store.transform[2],
|
||||||
@@ -90,7 +89,7 @@ const d = computed(() => {
|
|||||||
:viewBox="`${viewBox.x || 0} ${viewBox.y || 0} ${viewBox.width || 0} ${viewBox.height || 0}`"
|
:viewBox="`${viewBox.x || 0} ${viewBox.y || 0} ${viewBox.width || 0} ${viewBox.height || 0}`"
|
||||||
class="vue-flow__minimap"
|
class="vue-flow__minimap"
|
||||||
>
|
>
|
||||||
<template v-for="node of nodes" :key="`mini-map-node-${node.id}`">
|
<template v-for="node of store.getNodes" :key="`mini-map-node-${node.id}`">
|
||||||
<slot
|
<slot
|
||||||
:x="node.__vf.position.x"
|
:x="node.__vf.position.x"
|
||||||
:y="node.__vf.position.y"
|
:y="node.__vf.position.y"
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { getBezierPath, getSmoothStepPath } from '../Edges/utils'
|
import { getBezierPath, getSmoothStepPath } from '../Edges/utils'
|
||||||
import { useStore } from '../../composables'
|
import { useStore } from '../../composables'
|
||||||
import { ConnectionLineType, HandleElement, Node, Position } from '../../types'
|
import { ConnectionLineType, HandleElement, GraphNode, Position } from '../../types'
|
||||||
|
|
||||||
interface ConnectionLineProps {
|
interface ConnectionLineProps {
|
||||||
sourceNode: Node
|
sourceNode: GraphNode
|
||||||
connectionLineType?: ConnectionLineType
|
connectionLineType?: ConnectionLineType
|
||||||
connectionLineStyle?: CSSProperties
|
connectionLineStyle?: CSSProperties
|
||||||
}
|
}
|
||||||
@@ -19,29 +19,29 @@ const store = useStore()
|
|||||||
|
|
||||||
const sourceHandle =
|
const sourceHandle =
|
||||||
store.connectionHandleId && store.connectionHandleType
|
store.connectionHandleId && store.connectionHandleType
|
||||||
? props.sourceNode.__vf?.handleBounds[store.connectionHandleType].find(
|
? props.sourceNode.__vf.handleBounds[store.connectionHandleType]?.find(
|
||||||
(d: HandleElement) => d.id === store.connectionHandleId,
|
(d: HandleElement) => d.id === store.connectionHandleId,
|
||||||
)
|
)
|
||||||
: store.connectionHandleType && props.sourceNode.__vf?.handleBounds[store.connectionHandleType ?? 'source'][0]
|
: store.connectionHandleType && props.sourceNode.__vf.handleBounds[store.connectionHandleType ?? 'source']?.[0]
|
||||||
const sourceHandleX = sourceHandle ? sourceHandle.x + sourceHandle.width / 2 : (props.sourceNode.__vf?.width as number) / 2
|
const sourceHandleX = sourceHandle ? sourceHandle.x + sourceHandle.width / 2 : (props.sourceNode.__vf?.width as number) / 2
|
||||||
const sourceHandleY = sourceHandle ? sourceHandle.y + sourceHandle.height / 2 : props.sourceNode.__vf?.height
|
const sourceHandleY = sourceHandle ? sourceHandle.y + sourceHandle.height / 2 : props.sourceNode.__vf?.height
|
||||||
const sourceX = props.sourceNode.__vf?.position?.x + sourceHandleX
|
const sourceX = props.sourceNode.__vf?.position?.x + sourceHandleX
|
||||||
const sourceY = props.sourceNode.__vf?.position?.y + sourceHandleY
|
const sourceY = props.sourceNode.__vf?.position?.y + sourceHandleY
|
||||||
|
|
||||||
const isRightOrLeft = sourceHandle.position === Position.Left || sourceHandle.position === Position.Right
|
const isRightOrLeft = sourceHandle?.position === Position.Left || sourceHandle?.position === Position.Right
|
||||||
const targetPosition = isRightOrLeft ? Position.Left : Position.Top
|
const targetPosition = isRightOrLeft ? Position.Left : Position.Top
|
||||||
|
|
||||||
const targetX = computed(() => (store.connectionPosition.x - store.transform[0]) / store.transform[2])
|
const targetX = computed(() => (store.connectionPosition.x - store.transform[0]) / store.transform[2])
|
||||||
const targetY = computed(() => (store.connectionPosition.y - store.transform[1]) / store.transform[2])
|
const targetY = computed(() => (store.connectionPosition.y - store.transform[1]) / store.transform[2])
|
||||||
|
|
||||||
const dAttr = computed(() => {
|
const dAttr = computed(() => {
|
||||||
let path = `M${sourceX.value},${sourceY.value} ${targetX.value},${targetY.value}`
|
let path = `M${sourceX},${sourceY} ${targetX.value},${targetY.value}`
|
||||||
switch (props.connectionLineType) {
|
switch (props.connectionLineType) {
|
||||||
case ConnectionLineType.Bezier:
|
case ConnectionLineType.Bezier:
|
||||||
path = getBezierPath({
|
path = getBezierPath({
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
targetX: targetX.value,
|
targetX: targetX.value,
|
||||||
targetY: targetY.value,
|
targetY: targetY.value,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
@@ -51,7 +51,7 @@ const dAttr = computed(() => {
|
|||||||
path = getSmoothStepPath({
|
path = getSmoothStepPath({
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
targetX: targetX.value,
|
targetX: targetX.value,
|
||||||
targetY: targetY.value,
|
targetY: targetY.value,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
@@ -62,7 +62,7 @@ const dAttr = computed(() => {
|
|||||||
path = getSmoothStepPath({
|
path = getSmoothStepPath({
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
targetX: targetX.value,
|
targetX: targetX.value,
|
||||||
targetY: targetY.value,
|
targetY: targetY.value,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
@@ -78,7 +78,7 @@ const dAttr = computed(() => {
|
|||||||
v-bind="{
|
v-bind="{
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
targetX,
|
targetX,
|
||||||
targetY,
|
targetY,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useHandle, useStore } from '../../composables'
|
import { useHandle, useStore } from '../../composables'
|
||||||
import { ConnectionMode, Edge, EdgePositions, Position } from '../../types'
|
import { ConnectionMode, Edge, EdgePositions, Position } from '../../types'
|
||||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '../../container/EdgeRenderer/utils'
|
import { isEdge, getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '../../utils'
|
||||||
import { isEdge } from '../../utils'
|
|
||||||
import EdgeAnchor from './EdgeAnchor.vue'
|
import EdgeAnchor from './EdgeAnchor.vue'
|
||||||
|
|
||||||
interface EdgeProps {
|
interface EdgeWrapper {
|
||||||
edge: Edge
|
edge: Edge
|
||||||
markerEndId?: string
|
markerEndId?: string
|
||||||
edgeUpdaterRadius?: number
|
edgeUpdaterRadius?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<EdgeProps>(), {})
|
const props = withDefaults(defineProps<EdgeWrapper>(), {})
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
@@ -4,4 +4,4 @@ export { default as SmoothStepEdge } from './SmoothStepEdge.vue'
|
|||||||
export { default as StraightEdge } from './StraightEdge.vue'
|
export { default as StraightEdge } from './StraightEdge.vue'
|
||||||
export { default as EdgeAnchor } from './EdgeAnchor.vue'
|
export { default as EdgeAnchor } from './EdgeAnchor.vue'
|
||||||
export { default as EdgeText } from './EdgeText.vue'
|
export { default as EdgeText } from './EdgeText.vue'
|
||||||
export { default as EdgeWrapper } from './Edge.vue'
|
export { default as EdgeWrapper } from './EdgeWrapper.vue'
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { DraggableEventListener, DraggableCore } from '@braks/revue-draggable'
|
import { DraggableEventListener, DraggableCore } from '@braks/revue-draggable'
|
||||||
import { useStore } from '../../composables'
|
import { useStore } from '../../composables'
|
||||||
import { Node, SnapGrid } from '../../types'
|
import { GraphNode, SnapGrid } from '../../types'
|
||||||
import { NodeId } from '../../context'
|
import { NodeId } from '../../context'
|
||||||
|
|
||||||
interface NodeProps {
|
interface NodeWrapperProps {
|
||||||
node: Node
|
node: GraphNode
|
||||||
selectNodesOnDrag?: boolean
|
selectNodesOnDrag?: boolean
|
||||||
snapGrid?: SnapGrid
|
snapGrid?: SnapGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<NodeProps>(), {
|
const props = withDefaults(defineProps<NodeWrapperProps>(), {
|
||||||
selected: false,
|
selected: false,
|
||||||
selectNodesOnDrag: true,
|
selectNodesOnDrag: true,
|
||||||
})
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export { default as DefaultNode } from './DefaultNode.vue'
|
export { default as DefaultNode } from './DefaultNode.vue'
|
||||||
export { default as InputNode } from './InputNode.vue'
|
export { default as InputNode } from './InputNode.vue'
|
||||||
export { default as OutputNode } from './OutputNode.vue'
|
export { default as OutputNode } from './OutputNode.vue'
|
||||||
export { default as NodeWrapper } from './Node.vue'
|
export { default as NodeWrapper } from './NodeWrapper.vue'
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Draggable, DraggableEventListener } from '@braks/revue-draggable'
|
import { Draggable, DraggableEventListener } from '@braks/revue-draggable'
|
||||||
import { useStore } from '../../composables'
|
import { useStore } from '../../composables'
|
||||||
import { Node } from '../../types'
|
import { GraphNode } from '../../types'
|
||||||
import { getRectOfNodes, isNode } from '../../utils'
|
import { getRectOfNodes, isGraphNode } from '../../utils'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const selectedNodes = store.selectedElements
|
const selectedNodes: GraphNode[] = store.selectedElements
|
||||||
? store.selectedElements.filter(isNode).map((selectedNode) => {
|
? store.selectedElements.filter(isGraphNode).map((selectedNode) => {
|
||||||
const matchingNode = store.nodes.find((node) => node.id === selectedNode.id)
|
const matchingNode = store.nodes.find((node) => node.id === selectedNode.id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...matchingNode,
|
...matchingNode,
|
||||||
position: matchingNode?.__vf?.position,
|
position: matchingNode?.__vf?.position,
|
||||||
} as Node
|
} as GraphNode
|
||||||
})
|
})
|
||||||
: []
|
: []
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export * from './Nodes'
|
||||||
|
export * from './Edges'
|
||||||
|
export * from './ConnectionLine/ConnectionLine.vue'
|
||||||
|
export * from './Handle/Handle.vue'
|
||||||
|
export * from './Loading/LoadingIndicator.vue'
|
||||||
|
export * from './NodesSelection/NodesSelection.vue'
|
||||||
|
export * from './UserSelection/UserSelection.vue'
|
||||||
+39
-56
@@ -1,61 +1,44 @@
|
|||||||
import {
|
import { EmitFunc, FlowHooks, FlowEvents, FlowStore } from '~/types'
|
||||||
Connection,
|
|
||||||
Edge,
|
|
||||||
Elements,
|
|
||||||
EmitFunc,
|
|
||||||
FlowHooks,
|
|
||||||
FlowTransform,
|
|
||||||
Node,
|
|
||||||
OnConnectStartParams,
|
|
||||||
FlowInstance,
|
|
||||||
FlowEvents,
|
|
||||||
FlowStore,
|
|
||||||
} from '~/types'
|
|
||||||
|
|
||||||
// flow event hooks
|
// flow event hooks
|
||||||
export const createHooks = (): FlowHooks => {
|
export const createHooks = (): FlowHooks => ({
|
||||||
return {
|
elementClick: createEventHook(),
|
||||||
elementClick: createEventHook<{ event: MouseEvent; element: Node | Edge }>(),
|
elementsRemove: createEventHook(),
|
||||||
elementsRemove: createEventHook<Elements>(),
|
nodeDoubleClick: createEventHook(),
|
||||||
nodeDoubleClick: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeClick: createEventHook(),
|
||||||
nodeClick: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeMouseEnter: createEventHook(),
|
||||||
nodeMouseEnter: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeMouseMove: createEventHook(),
|
||||||
nodeMouseMove: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeMouseLeave: createEventHook(),
|
||||||
nodeMouseLeave: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeContextMenu: createEventHook(),
|
||||||
nodeContextMenu: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeDragStart: createEventHook(),
|
||||||
nodeDragStart: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeDrag: createEventHook(),
|
||||||
nodeDrag: createEventHook<{ event: MouseEvent; node: Node }>(),
|
nodeDragStop: createEventHook(),
|
||||||
nodeDragStop: createEventHook<{ event: MouseEvent; node: Node }>(),
|
connect: createEventHook(),
|
||||||
connect: createEventHook<Connection>(),
|
connectStart: createEventHook(),
|
||||||
connectStart: createEventHook<{
|
connectStop: createEventHook(),
|
||||||
event: MouseEvent
|
connectEnd: createEventHook(),
|
||||||
params: OnConnectStartParams
|
load: createEventHook(),
|
||||||
}>(),
|
move: createEventHook(),
|
||||||
connectStop: createEventHook<MouseEvent>(),
|
moveStart: createEventHook(),
|
||||||
connectEnd: createEventHook<MouseEvent>(),
|
moveEnd: createEventHook(),
|
||||||
load: createEventHook<FlowInstance>(),
|
selectionChange: createEventHook(),
|
||||||
move: createEventHook<FlowTransform | undefined>(),
|
selectionDragStart: createEventHook(),
|
||||||
moveStart: createEventHook<FlowTransform | undefined>(),
|
selectionDrag: createEventHook(),
|
||||||
moveEnd: createEventHook<FlowTransform | undefined>(),
|
selectionDragStop: createEventHook(),
|
||||||
selectionChange: createEventHook<Elements | null>(),
|
selectionContextMenu: createEventHook(),
|
||||||
selectionDragStart: createEventHook<{ event: MouseEvent; nodes: Node[] }>(),
|
paneScroll: createEventHook(),
|
||||||
selectionDrag: createEventHook<{ event: MouseEvent; nodes: Node[] }>(),
|
paneClick: createEventHook(),
|
||||||
selectionDragStop: createEventHook<{ event: MouseEvent; nodes: Node[] }>(),
|
paneContextMenu: createEventHook(),
|
||||||
selectionContextMenu: createEventHook<{ event: MouseEvent; nodes: Node[] }>(),
|
edgeUpdate: createEventHook(),
|
||||||
paneScroll: createEventHook<WheelEvent | undefined>(),
|
edgeContextMenu: createEventHook(),
|
||||||
paneClick: createEventHook<MouseEvent>(),
|
edgeMouseEnter: createEventHook(),
|
||||||
paneContextMenu: createEventHook<MouseEvent>(),
|
edgeMouseMove: createEventHook(),
|
||||||
edgeUpdate: createEventHook<{ edge: Edge; connection: Connection }>(),
|
edgeMouseLeave: createEventHook(),
|
||||||
edgeContextMenu: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
edgeDoubleClick: createEventHook(),
|
||||||
edgeMouseEnter: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
edgeClick: createEventHook(),
|
||||||
edgeMouseMove: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
edgeUpdateStart: createEventHook(),
|
||||||
edgeMouseLeave: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
edgeUpdateEnd: createEventHook(),
|
||||||
edgeDoubleClick: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
})
|
||||||
edgeClick: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
|
||||||
edgeUpdateStart: createEventHook<{ event: MouseEvent; edge: Edge }>(),
|
|
||||||
edgeUpdateEnd: createEventHook<MouseEvent>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bind = (emit: EmitFunc, hooks: FlowHooks) => {
|
const bind = (emit: EmitFunc, hooks: FlowHooks) => {
|
||||||
for (const [key, value] of Object.entries(hooks)) {
|
for (const [key, value] of Object.entries(hooks)) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { FlowExportObject, FlowOptions } from '~/types'
|
import { FlowExportObject, FlowOptions, FlowState } from '~/types'
|
||||||
import { useStateStore, initialState } from '~/store'
|
import { useStateStore } from '~/store'
|
||||||
import { Store } from '~/context'
|
import { Store } from '~/context'
|
||||||
import { onLoadToObject } from '~/utils'
|
import { onLoadToObject, initialState } from '~/utils'
|
||||||
|
|
||||||
let id = 0
|
let id = 0
|
||||||
export default (options?: Partial<FlowOptions>, key?: string) => {
|
export default (options?: Partial<FlowOptions>, key?: string) => {
|
||||||
@@ -15,10 +15,10 @@ export default (options?: Partial<FlowOptions>, key?: string) => {
|
|||||||
const storageKey = key ?? `vue-flow-${id++}`
|
const storageKey = key ?? `vue-flow-${id++}`
|
||||||
const preloadedState = {
|
const preloadedState = {
|
||||||
...initial,
|
...initial,
|
||||||
...options,
|
...(options as FlowState),
|
||||||
}
|
}
|
||||||
if (withStorage) {
|
if (withStorage) {
|
||||||
storedState = useStorage(storageKey, {} as FlowExportObject)
|
storedState = useStorage<FlowExportObject>(storageKey, { elements: [], position: [0, 0], zoom: 0 })
|
||||||
if (storedState.value) {
|
if (storedState.value) {
|
||||||
preloadedState.elements = storedState.value.elements ?? options?.elements ?? []
|
preloadedState.elements = storedState.value.elements ?? options?.elements ?? []
|
||||||
if (storedState.value.position && storedState.value.zoom)
|
if (storedState.value.position && storedState.value.zoom)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import { zoomIdentity } from 'd3-zoom'
|
import { zoomIdentity } from 'd3-zoom'
|
||||||
import useStore from './useStore'
|
import useStore from './useStore'
|
||||||
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils'
|
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { ConnectionLineType } from '../../types'
|
import { ConnectionLineType } from '../../types'
|
||||||
import { useStore } from '../../composables'
|
import { useStore } from '../../composables'
|
||||||
import Edge from '../../components/Edges/Edge.vue'
|
import Edge from '../../components/Edges/EdgeWrapper.vue'
|
||||||
import ConnectionLine from '../../components/ConnectionLine/ConnectionLine.vue'
|
import ConnectionLine from '../../components/ConnectionLine/ConnectionLine.vue'
|
||||||
import MarkerDefinitions from './MarkerDefinitions.vue'
|
import MarkerDefinitions from './MarkerDefinitions.vue'
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useStore } from '../../composables'
|
import { useStore } from '../../composables'
|
||||||
import Node from '../../components/Nodes/Node.vue'
|
import Node from '../../components/Nodes/NodeWrapper.vue'
|
||||||
|
import { SnapGrid } from '../../types'
|
||||||
|
|
||||||
interface NodeRendererProps {
|
interface NodeRendererProps {
|
||||||
selectNodesOnDrag?: boolean
|
selectNodesOnDrag?: boolean
|
||||||
|
snapToGrid?: boolean
|
||||||
|
snapGrid?: SnapGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<NodeRendererProps>(), {
|
const props = withDefaults(defineProps<NodeRendererProps>(), {
|
||||||
@@ -13,7 +16,7 @@ const props = withDefaults(defineProps<NodeRendererProps>(), {
|
|||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`)
|
const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`)
|
||||||
const snapGrid = computed(() => (store.snapToGrid ? store.snapGrid : undefined))
|
const snapGrid = computed(() => (props.snapToGrid || store.snapToGrid ? props.snapGrid ?? store.snapGrid : undefined))
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="vue-flow__nodes" :style="{ transform }">
|
<div class="vue-flow__nodes" :style="{ transform }">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ElementId, FlowElement, KeyCode } from '../../types'
|
|||||||
import { useStore, useKeyPress } from '../../composables'
|
import { useStore, useKeyPress } from '../../composables'
|
||||||
import NodesSelection from '../../components/NodesSelection/NodesSelection.vue'
|
import NodesSelection from '../../components/NodesSelection/NodesSelection.vue'
|
||||||
import UserSelection from '../../components/UserSelection/UserSelection.vue'
|
import UserSelection from '../../components/UserSelection/UserSelection.vue'
|
||||||
import { getConnectedEdges, isNode } from '../../utils'
|
import { getConnectedEdges, isGraphNode } from '../../utils'
|
||||||
|
|
||||||
interface SelectionPaneProps {
|
interface SelectionPaneProps {
|
||||||
selectionKeyCode?: KeyCode
|
selectionKeyCode?: KeyCode
|
||||||
@@ -33,7 +33,7 @@ const selectionKeyPresed = ref(false)
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
useKeyPress(props.deleteKeyCode, (keyPressed) => {
|
useKeyPress(props.deleteKeyCode, (keyPressed) => {
|
||||||
if (keyPressed && store.selectedElements) {
|
if (keyPressed && store.selectedElements) {
|
||||||
const selectedNodes = store.selectedElements.filter(isNode)
|
const selectedNodes = store.selectedElements.filter(isGraphNode)
|
||||||
const connectedEdges = getConnectedEdges(selectedNodes, store.edges)
|
const connectedEdges = getConnectedEdges(selectedNodes, store.edges)
|
||||||
const elementsToRemove = [...store.selectedElements, ...connectedEdges].reduce(
|
const elementsToRemove = [...store.selectedElements, ...connectedEdges].reduce(
|
||||||
(res, item) => res.set(item.id, item),
|
(res, item) => res.set(item.id, item),
|
||||||
|
|||||||
@@ -181,7 +181,6 @@ const transitionName = computed(() => {
|
|||||||
<Suspense>
|
<Suspense>
|
||||||
<template #default>
|
<template #default>
|
||||||
<ZoomPane
|
<ZoomPane
|
||||||
v-show="store.isReady"
|
|
||||||
key="zoom-pane"
|
key="zoom-pane"
|
||||||
:selection-key-code="store.selectionKeyCode"
|
:selection-key-code="store.selectionKeyCode"
|
||||||
:zoom-activation-key-code="store.zoomActivationKeyCode"
|
:zoom-activation-key-code="store.zoomActivationKeyCode"
|
||||||
|
|||||||
+1
-2
@@ -20,11 +20,10 @@ export {
|
|||||||
isInputDOMNode,
|
isInputDOMNode,
|
||||||
graphPosToZoomedPos,
|
graphPosToZoomedPos,
|
||||||
} from './utils/graph'
|
} from './utils/graph'
|
||||||
|
export { defaultEdgeTypes, defaultNodeTypes } from './utils/store'
|
||||||
export { default as useZoomPanHelper } from './composables/useZoomPanHelper'
|
export { default as useZoomPanHelper } from './composables/useZoomPanHelper'
|
||||||
export { default as useVueFlow } from './composables/useVueFlow'
|
export { default as useVueFlow } from './composables/useVueFlow'
|
||||||
export { default as useHandle } from './composables/useHandle'
|
export { default as useHandle } from './composables/useHandle'
|
||||||
export { default as useKeyPress } from './composables/useKeyPress'
|
|
||||||
export { defaultEdgeTypes, defaultNodeTypes } from './store'
|
|
||||||
|
|
||||||
export * from './additional-components'
|
export * from './additional-components'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export { default as useStateStore } from './stateStore'
|
export { default as useStateStore } from './stateStore'
|
||||||
export { defaultEdgeTypes, defaultNodeTypes, initialState } from './utils'
|
|
||||||
|
|||||||
+22
-19
@@ -1,9 +1,20 @@
|
|||||||
import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia'
|
import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia'
|
||||||
import microDiff from 'microdiff'
|
import microDiff from 'microdiff'
|
||||||
import { parseElements, defaultNodeTypes, defaultEdgeTypes, deepUnref, NextElements } from './utils'
|
import { FlowState, Node, FlowActions, Elements, FlowGetters, Edge, GraphNode, NextElements } from '~/types'
|
||||||
import { FlowState, Node, FlowActions, Elements, FlowGetters, Edge } from '~/types'
|
import {
|
||||||
import { clampPosition, getDimensions, getConnectedEdges, getNodesInside, getRectOfNodes, isNode } from '~/utils'
|
clampPosition,
|
||||||
import { getHandleBounds } from '~/components/Nodes/utils'
|
getDimensions,
|
||||||
|
getConnectedEdges,
|
||||||
|
getNodesInside,
|
||||||
|
getRectOfNodes,
|
||||||
|
isNode,
|
||||||
|
parseElements,
|
||||||
|
defaultNodeTypes,
|
||||||
|
defaultEdgeTypes,
|
||||||
|
deepUnref,
|
||||||
|
getHandleBounds,
|
||||||
|
isGraphNode,
|
||||||
|
} from '~/utils'
|
||||||
import parseElementsWorker from '~/workers/parseElements'
|
import parseElementsWorker from '~/workers/parseElements'
|
||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
@@ -81,7 +92,7 @@ export default function flowStore(
|
|||||||
} else next = await parseElements(elements, this.nodes, this.edges, this.nodeExtent)
|
} else next = await parseElements(elements, this.nodes, this.edges, this.nodeExtent)
|
||||||
}
|
}
|
||||||
if (next) {
|
if (next) {
|
||||||
this.elements = elements ?? []
|
this.elements = [...next.nextNodes, ...next.nextEdges]
|
||||||
this.nodes = next?.nextNodes ?? []
|
this.nodes = next?.nextNodes ?? []
|
||||||
this.edges = next?.nextEdges ?? []
|
this.edges = next?.nextEdges ?? []
|
||||||
}
|
}
|
||||||
@@ -102,7 +113,6 @@ export default function flowStore(
|
|||||||
this.nodes.splice(i, 1, {
|
this.nodes.splice(i, 1, {
|
||||||
...node,
|
...node,
|
||||||
__vf: {
|
__vf: {
|
||||||
position: { x: 0, y: 0 },
|
|
||||||
...node.__vf,
|
...node.__vf,
|
||||||
...dimensions,
|
...dimensions,
|
||||||
handleBounds,
|
handleBounds,
|
||||||
@@ -125,21 +135,16 @@ export default function flowStore(
|
|||||||
this.nodes.splice(i, 1, {
|
this.nodes.splice(i, 1, {
|
||||||
...node,
|
...node,
|
||||||
__vf: {
|
__vf: {
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
...node.__vf,
|
...node.__vf,
|
||||||
position: pos,
|
position: pos,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateNodePosDiff({ id, diff, isDragging }) {
|
updateNodePosDiff({ id, diff, isDragging }) {
|
||||||
const update = (node: Node, i: number) => {
|
const update = (node: GraphNode, i: number) => {
|
||||||
const updatedNode: Node = {
|
const updatedNode: GraphNode = {
|
||||||
...node,
|
...node,
|
||||||
__vf: {
|
__vf: {
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
position: { x: 0, y: 0 },
|
|
||||||
...node.__vf,
|
...node.__vf,
|
||||||
isDragging,
|
isDragging,
|
||||||
},
|
},
|
||||||
@@ -161,8 +166,8 @@ export default function flowStore(
|
|||||||
if (!id) {
|
if (!id) {
|
||||||
const selectedNodes = this.nodes.filter((x) => this.selectedElements?.find((sNode) => sNode?.id === x.id))
|
const selectedNodes = this.nodes.filter((x) => this.selectedElements?.find((sNode) => sNode?.id === x.id))
|
||||||
selectedNodes.forEach((node) => {
|
selectedNodes.forEach((node) => {
|
||||||
const i = this.nodes.map((x) => x.id).indexOf((node as Node).id)
|
const i = this.nodes.map((x) => x.id).indexOf(node.id)
|
||||||
update(node as Node, i)
|
update(node, i)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const i = this.nodes.map((x) => x.id).indexOf(id)
|
const i = this.nodes.map((x) => x.id).indexOf(id)
|
||||||
@@ -202,7 +207,7 @@ export default function flowStore(
|
|||||||
this.selectedElements = nextSelectedElements
|
this.selectedElements = nextSelectedElements
|
||||||
},
|
},
|
||||||
unsetUserSelection() {
|
unsetUserSelection() {
|
||||||
const selectedNodes = this.selectedElements?.filter((node) => node && isNode(node) && node.__vf) as Node[]
|
const selectedNodes = this.selectedElements?.filter((node) => node && isGraphNode(node) && node.__vf) as GraphNode[]
|
||||||
|
|
||||||
this.selectionActive = false
|
this.selectionActive = false
|
||||||
this.userSelectionRect.draw = false
|
this.userSelectionRect.draw = false
|
||||||
@@ -243,8 +248,6 @@ export default function flowStore(
|
|||||||
return {
|
return {
|
||||||
...node,
|
...node,
|
||||||
__vf: {
|
__vf: {
|
||||||
height: 0,
|
|
||||||
width: 0,
|
|
||||||
...node.__vf,
|
...node.__vf,
|
||||||
position: node.__vf?.position ? clampPosition(node.__vf.position, nodeExtent) : { x: 0, y: 0 },
|
position: node.__vf?.position ? clampPosition(node.__vf.position, nodeExtent) : { x: 0, y: 0 },
|
||||||
},
|
},
|
||||||
@@ -272,7 +275,7 @@ export default function flowStore(
|
|||||||
},
|
},
|
||||||
async addElements(elements: Elements) {
|
async addElements(elements: Elements) {
|
||||||
const { nextNodes, nextEdges } = await parseElements(elements, this.nodes, this.edges, this.nodeExtent)
|
const { nextNodes, nextEdges } = await parseElements(elements, this.nodes, this.edges, this.nodeExtent)
|
||||||
this.elements = [...this.elements, ...elements]
|
this.elements = [...this.elements, ...nextNodes, ...nextEdges]
|
||||||
this.nodes = [...this.nodes, ...nextNodes]
|
this.nodes = [...this.nodes, ...nextNodes]
|
||||||
this.edges = [...this.edges, ...nextEdges]
|
this.edges = [...this.edges, ...nextEdges]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { Dimensions, Elements, XYPosition } from './types'
|
|
||||||
import { NodeDiffUpdate, NodeDimensionUpdate, NodeExtent, NodePosUpdate, TranslateExtent } from './node'
|
|
||||||
import { InitD3ZoomPayload } from './panel'
|
|
||||||
import { SetConnectionId } from './connection'
|
|
||||||
|
|
||||||
export interface FlowActions {
|
|
||||||
setElements: (elements: Elements) => void
|
|
||||||
updateNodeDimensions: (update: NodeDimensionUpdate) => void
|
|
||||||
updateNodePos: (payload: NodePosUpdate) => void
|
|
||||||
updateNodePosDiff: (payload: NodeDiffUpdate) => void
|
|
||||||
setUserSelection: (mousePos: XYPosition) => void
|
|
||||||
updateUserSelection: (mousePos: XYPosition) => void
|
|
||||||
unsetUserSelection: () => void
|
|
||||||
addSelectedElements: (elements: Elements) => void
|
|
||||||
initD3Zoom: (payload: InitD3ZoomPayload) => void
|
|
||||||
setMinZoom: (zoom: number) => void
|
|
||||||
setMaxZoom: (zoom: number) => void
|
|
||||||
setTranslateExtent: (translateExtent: TranslateExtent) => void
|
|
||||||
setNodeExtent: (nodeExtent: NodeExtent) => void
|
|
||||||
resetSelectedElements: () => void
|
|
||||||
unsetNodesSelection: () => void
|
|
||||||
updateSize: (size: Dimensions) => void
|
|
||||||
setConnectionNodeId: (payload: SetConnectionId) => void
|
|
||||||
setInteractive: (isInteractive: boolean) => void
|
|
||||||
addElements: (elements: Elements) => void
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ElementId, Position } from './types'
|
import { ElementId, Position } from './flow'
|
||||||
import { HandleType } from './handle'
|
import { HandleType } from './handle'
|
||||||
|
|
||||||
export enum ConnectionLineType {
|
export enum ConnectionLineType {
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import { Component, CSSProperties, DefineComponent } from 'vue'
|
import { Component, CSSProperties, DefineComponent } from 'vue'
|
||||||
import { ArrowHeadType, ElementId, Position } from './types'
|
import { ArrowHeadType, ElementId, Position } from './flow'
|
||||||
|
|
||||||
export interface Edge<T = any> {
|
export interface Edge<T = any> {
|
||||||
id: ElementId
|
id: ElementId
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { Edge, EdgeTypes } from './edge'
|
import { Edge, EdgeTypes } from './edge'
|
||||||
import { Node, NodeExtent, NodeTypes, TranslateExtent } from './node'
|
import { NodeExtent, GraphNode, NodeTypes, TranslateExtent, Node } from './node'
|
||||||
import { ConnectionLineType, ConnectionMode } from './connection'
|
import { ConnectionLineType, ConnectionMode } from './connection'
|
||||||
import { KeyCode, PanOnScrollMode } from './panel'
|
import { KeyCode, PanOnScrollMode } from './zoom'
|
||||||
import { FlowStore } from './store'
|
import { FlowStore } from './store'
|
||||||
|
|
||||||
export type ElementId = string
|
export type ElementId = string
|
||||||
|
export type FlowElement<T = any> = GraphNode<T> | Edge<T>
|
||||||
export type FlowElement<T = any> = Node<T> | Edge<T>
|
export type FlowElements<T = any> = FlowElement<T>[]
|
||||||
|
export type Elements<T = any> = (Node<T> | Edge<T>)[]
|
||||||
export type Elements<T = any> = FlowElement<T>[]
|
export type NextElements = {
|
||||||
|
nextNodes: GraphNode[]
|
||||||
|
nextEdges: Edge[]
|
||||||
|
}
|
||||||
|
|
||||||
export type Transform = [number, number, number]
|
export type Transform = [number, number, number]
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@ export type FitViewParams = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type FlowExportObject<T = any> = {
|
export type FlowExportObject<T = any> = {
|
||||||
elements: Elements<T>
|
elements: FlowElements<T>
|
||||||
position: [number, number]
|
position: [number, number]
|
||||||
zoom: number
|
zoom: number
|
||||||
}
|
}
|
||||||
@@ -98,14 +101,13 @@ export type FlowInstance<T = any> = {
|
|||||||
zoomTo: (zoomLevel: number) => void
|
zoomTo: (zoomLevel: number) => void
|
||||||
fitView: FitViewFunc
|
fitView: FitViewFunc
|
||||||
project: ProjectFunc
|
project: ProjectFunc
|
||||||
getElements: () => Elements<T>
|
getElements: () => FlowElements<T>
|
||||||
setTransform: (transform: FlowTransform) => void
|
setTransform: (transform: FlowTransform) => void
|
||||||
toObject: ToObjectFunc<T>
|
toObject: ToObjectFunc<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FlowOptions {
|
export interface FlowOptions {
|
||||||
id?: string
|
id?: string
|
||||||
store?: FlowStore
|
|
||||||
elements?: Elements
|
elements?: Elements
|
||||||
nodeTypes?: NodeTypes
|
nodeTypes?: NodeTypes
|
||||||
edgeTypes?: EdgeTypes
|
edgeTypes?: EdgeTypes
|
||||||
@@ -142,4 +144,5 @@ export interface FlowOptions {
|
|||||||
storageKey?: string
|
storageKey?: string
|
||||||
loading?: Loading
|
loading?: Loading
|
||||||
worker?: boolean
|
worker?: boolean
|
||||||
|
store?: FlowStore
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import { Dimensions, ElementId, Position, XYPosition } from './types'
|
import { Dimensions, ElementId, Position, XYPosition } from './flow'
|
||||||
import { Connection } from '~/types/connection'
|
import { Connection } from './connection'
|
||||||
|
|
||||||
export type HandleType = 'source' | 'target'
|
export type HandleType = 'source' | 'target'
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
import { EventHook } from '@vueuse/core'
|
import { EventHook } from '@vueuse/core'
|
||||||
import { Elements, FlowTransform, FlowInstance } from './types'
|
import { FlowTransform, FlowInstance, FlowElements } from './flow'
|
||||||
import { Edge } from './edge'
|
import { Edge } from './edge'
|
||||||
import { Node } from './node'
|
import { Node } from './node'
|
||||||
import { Connection, OnConnectStartParams } from './connection'
|
import { Connection, OnConnectStartParams } from './connection'
|
||||||
@@ -8,7 +8,7 @@ export type FlowHook<T = any> = EventHook<T>
|
|||||||
|
|
||||||
export interface FlowEvents {
|
export interface FlowEvents {
|
||||||
elementClick: { event: MouseEvent; element: Node | Edge }
|
elementClick: { event: MouseEvent; element: Node | Edge }
|
||||||
elementsRemove: Elements
|
elementsRemove: FlowElements
|
||||||
nodeDoubleClick: { event: MouseEvent; node: Node }
|
nodeDoubleClick: { event: MouseEvent; node: Node }
|
||||||
nodeClick: { event: MouseEvent; node: Node }
|
nodeClick: { event: MouseEvent; node: Node }
|
||||||
nodeMouseEnter: { event: MouseEvent; node: Node }
|
nodeMouseEnter: { event: MouseEvent; node: Node }
|
||||||
@@ -29,7 +29,7 @@ export interface FlowEvents {
|
|||||||
move: FlowTransform | undefined
|
move: FlowTransform | undefined
|
||||||
moveStart: FlowTransform | undefined
|
moveStart: FlowTransform | undefined
|
||||||
moveEnd: FlowTransform | undefined
|
moveEnd: FlowTransform | undefined
|
||||||
selectionChange: Elements | null
|
selectionChange: FlowElements | null
|
||||||
selectionDragStart: { event: MouseEvent; nodes: Node[] }
|
selectionDragStart: { event: MouseEvent; nodes: Node[] }
|
||||||
selectionDrag: { event: MouseEvent; nodes: Node[] }
|
selectionDrag: { event: MouseEvent; nodes: Node[] }
|
||||||
selectionDragStop: { event: MouseEvent; nodes: Node[] }
|
selectionDragStop: { event: MouseEvent; nodes: Node[] }
|
||||||
|
|||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
export * from './types'
|
export * from './flow'
|
||||||
export * from './actions'
|
|
||||||
export * from './connection'
|
export * from './connection'
|
||||||
export * from './edge'
|
export * from './edge'
|
||||||
export * from './handle'
|
export * from './handle'
|
||||||
export * from './node'
|
export * from './node'
|
||||||
export * from './panel'
|
export * from './zoom'
|
||||||
export * from './store'
|
export * from './store'
|
||||||
export * from './hooks'
|
export * from './hooks'
|
||||||
|
|||||||
+17
-12
@@ -1,21 +1,22 @@
|
|||||||
import { Component, CSSProperties, DefineComponent } from 'vue'
|
import { Component, CSSProperties, DefineComponent } from 'vue'
|
||||||
import { XYPosition, ElementId, Position } from './types'
|
import { XYPosition, ElementId, Position } from './flow'
|
||||||
import { HandleElement } from '~/types/handle'
|
import { HandleElement } from './handle'
|
||||||
|
|
||||||
|
interface VFInternals {
|
||||||
|
position: XYPosition
|
||||||
|
isDragging?: boolean
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
handleBounds: {
|
||||||
|
source: HandleElement[] | null
|
||||||
|
target: HandleElement[] | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface Node<T = any> {
|
export interface Node<T = any> {
|
||||||
id: ElementId
|
id: ElementId
|
||||||
position: XYPosition
|
position: XYPosition
|
||||||
type?: string
|
type?: string
|
||||||
__vf?: {
|
|
||||||
position: XYPosition
|
|
||||||
isDragging?: boolean
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
handleBounds?: {
|
|
||||||
source?: HandleElement[] | null
|
|
||||||
target?: HandleElement[] | null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class?: string
|
class?: string
|
||||||
style?: CSSProperties
|
style?: CSSProperties
|
||||||
data?: T
|
data?: T
|
||||||
@@ -27,6 +28,10 @@ export interface Node<T = any> {
|
|||||||
connectable?: boolean
|
connectable?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GraphNode<T = any> extends Node<T> {
|
||||||
|
__vf: VFInternals
|
||||||
|
}
|
||||||
|
|
||||||
export type NodePosUpdate = {
|
export type NodePosUpdate = {
|
||||||
id: ElementId
|
id: ElementId
|
||||||
pos: XYPosition
|
pos: XYPosition
|
||||||
|
|||||||
+38
-9
@@ -3,6 +3,7 @@ import {
|
|||||||
Dimensions,
|
Dimensions,
|
||||||
ElementId,
|
ElementId,
|
||||||
Elements,
|
Elements,
|
||||||
|
FlowElements,
|
||||||
FlowInstance,
|
FlowInstance,
|
||||||
FlowOptions,
|
FlowOptions,
|
||||||
Rect,
|
Rect,
|
||||||
@@ -10,20 +11,26 @@ import {
|
|||||||
SnapGrid,
|
SnapGrid,
|
||||||
Transform,
|
Transform,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
} from './types'
|
} from './flow'
|
||||||
import { HandleType } from './handle'
|
import { HandleType } from './handle'
|
||||||
import { ConnectionMode, OnConnectEndFunc, OnConnectFunc, OnConnectStartFunc, OnConnectStopFunc } from './connection'
|
import {
|
||||||
|
ConnectionMode,
|
||||||
|
OnConnectEndFunc,
|
||||||
|
OnConnectFunc,
|
||||||
|
OnConnectStartFunc,
|
||||||
|
OnConnectStopFunc,
|
||||||
|
SetConnectionId,
|
||||||
|
} from './connection'
|
||||||
import { Edge, EdgeComponent } from './edge'
|
import { Edge, EdgeComponent } from './edge'
|
||||||
import { Node, NodeComponent, NodeExtent, TranslateExtent } from './node'
|
import { NodeComponent, NodeDiffUpdate, NodeDimensionUpdate, NodeExtent, GraphNode, NodePosUpdate, TranslateExtent } from './node'
|
||||||
import { FlowActions } from './actions'
|
import { D3Selection, D3Zoom, D3ZoomHandler, InitD3ZoomPayload } from './zoom'
|
||||||
import { D3Selection, D3Zoom, D3ZoomHandler } from './panel'
|
|
||||||
import { FlowHooks } from './hooks'
|
import { FlowHooks } from './hooks'
|
||||||
|
|
||||||
export interface FlowState extends FlowOptions {
|
export interface FlowState extends FlowOptions {
|
||||||
elements: Elements
|
elements: FlowElements
|
||||||
nodes: Node[]
|
nodes: GraphNode[]
|
||||||
edges: Edge[]
|
edges: Edge[]
|
||||||
selectedElements?: Elements
|
selectedElements?: FlowElements
|
||||||
selectedNodesBbox: Rect
|
selectedNodesBbox: Rect
|
||||||
|
|
||||||
d3Zoom?: D3Zoom
|
d3Zoom?: D3Zoom
|
||||||
@@ -66,10 +73,32 @@ export interface FlowState extends FlowOptions {
|
|||||||
vueFlowVersion: string
|
vueFlowVersion: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FlowActions {
|
||||||
|
setElements: (elements: Elements) => Promise<void>
|
||||||
|
updateNodeDimensions: (update: NodeDimensionUpdate) => void
|
||||||
|
updateNodePos: (payload: NodePosUpdate) => void
|
||||||
|
updateNodePosDiff: (payload: NodeDiffUpdate) => void
|
||||||
|
setUserSelection: (mousePos: XYPosition) => void
|
||||||
|
updateUserSelection: (mousePos: XYPosition) => void
|
||||||
|
unsetUserSelection: () => void
|
||||||
|
addSelectedElements: (elements: FlowElements) => void
|
||||||
|
initD3Zoom: (payload: InitD3ZoomPayload) => void
|
||||||
|
setMinZoom: (zoom: number) => void
|
||||||
|
setMaxZoom: (zoom: number) => void
|
||||||
|
setTranslateExtent: (translateExtent: TranslateExtent) => void
|
||||||
|
setNodeExtent: (nodeExtent: NodeExtent) => void
|
||||||
|
resetSelectedElements: () => void
|
||||||
|
unsetNodesSelection: () => void
|
||||||
|
updateSize: (size: Dimensions) => void
|
||||||
|
setConnectionNodeId: (payload: SetConnectionId) => void
|
||||||
|
setInteractive: (isInteractive: boolean) => void
|
||||||
|
addElements: (elements: Elements) => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
export interface FlowGetters {
|
export interface FlowGetters {
|
||||||
getEdgeTypes: () => Record<string, EdgeComponent>
|
getEdgeTypes: () => Record<string, EdgeComponent>
|
||||||
getNodeTypes: () => Record<string, NodeComponent>
|
getNodeTypes: () => Record<string, NodeComponent>
|
||||||
getNodes: () => Node[]
|
getNodes: () => GraphNode[]
|
||||||
getEdges: () => Edge[]
|
getEdges: () => Edge[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Selection, ZoomBehavior } from 'd3'
|
import { Selection, ZoomBehavior } from 'd3'
|
||||||
import { FitViewFunc, FlowTransform, Rect, XYPosition } from './types'
|
import { FitViewFunc, FlowTransform, Rect, XYPosition } from './flow'
|
||||||
|
|
||||||
export type D3Zoom = ZoomBehavior<HTMLDivElement, unknown>
|
export type D3Zoom = ZoomBehavior<HTMLDivElement, unknown>
|
||||||
export type D3Selection = Selection<HTMLDivElement, unknown, any, any>
|
export type D3Selection = Selection<HTMLDivElement, unknown, any, any>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Edge, EdgePositions, ElementId, HandleElement, Node, Position, Transform, XYPosition } from '../../types'
|
import { rectToBox } from './graph'
|
||||||
import { rectToBox } from '~/utils'
|
import { Edge, EdgePositions, ElementId, GraphNode, HandleElement, Position, Transform, XYPosition } from '~/types'
|
||||||
|
|
||||||
export function getHandlePosition(position: Position, node: Node, handle: any | null = null): XYPosition {
|
export function getHandlePosition(position: Position, node: GraphNode, handle: any | null = null): XYPosition {
|
||||||
const x = (handle?.x || 0) + node.__vf?.position?.x
|
const x = (handle?.x || 0) + node.__vf.position.x
|
||||||
const y = (handle?.y || 0) + node.__vf?.position?.y
|
const y = (handle?.y || 0) + node.__vf.position.y
|
||||||
const width = handle?.width || node.__vf?.width
|
const width = handle?.width || node.__vf.width
|
||||||
const height = handle?.height || node.__vf?.height
|
const height = handle?.height || node.__vf.height
|
||||||
|
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case Position.Top:
|
case Position.Top:
|
||||||
@@ -47,10 +47,10 @@ export function getHandle(bounds: HandleElement[], handleId: ElementId | null):
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getEdgePositions = (
|
export const getEdgePositions = (
|
||||||
sourceNode: Node,
|
sourceNode: GraphNode,
|
||||||
sourceHandle: HandleElement | unknown,
|
sourceHandle: HandleElement | unknown,
|
||||||
sourcePosition: Position,
|
sourcePosition: Position,
|
||||||
targetNode: Node,
|
targetNode: GraphNode,
|
||||||
targetHandle: HandleElement | unknown,
|
targetHandle: HandleElement | unknown,
|
||||||
targetPosition: Position,
|
targetPosition: Position,
|
||||||
): EdgePositions => {
|
): EdgePositions => {
|
||||||
@@ -104,11 +104,11 @@ export function isEdgeVisible({ sourcePos, targetPos, width, height, transform }
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SourceTargetNode = {
|
type SourceTargetNode = {
|
||||||
sourceNode: Node
|
sourceNode: GraphNode
|
||||||
targetNode: Node
|
targetNode: GraphNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSourceTargetNodes = (edge: Edge, nodes: Node[]): SourceTargetNode => {
|
export const getSourceTargetNodes = (edge: Edge, nodes: GraphNode[]): SourceTargetNode => {
|
||||||
return nodes.reduce(
|
return nodes.reduce(
|
||||||
(res, node) => {
|
(res, node) => {
|
||||||
if (node.id === edge.source) {
|
if (node.id === edge.source) {
|
||||||
+42
-45
@@ -12,12 +12,20 @@ import {
|
|||||||
NodeExtent,
|
NodeExtent,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
FlowStore,
|
FlowStore,
|
||||||
|
GraphNode,
|
||||||
|
FlowElements,
|
||||||
|
FlowElement,
|
||||||
} from '~/types'
|
} from '~/types'
|
||||||
import { useWindow } from '~/composables'
|
import { useWindow } from '~/composables'
|
||||||
|
|
||||||
|
const isHTMLElement = (el: EventTarget): el is HTMLElement => ('nodeName' || 'hasAttribute') in el
|
||||||
|
|
||||||
export const isInputDOMNode = (e: KeyboardEvent | MouseEvent): boolean => {
|
export const isInputDOMNode = (e: KeyboardEvent | MouseEvent): boolean => {
|
||||||
const target = e.target as HTMLElement
|
const target = e.target
|
||||||
return ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].includes(target.nodeName) || target.hasAttribute('contentEditable')
|
if (target && isHTMLElement(target)) {
|
||||||
|
return ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].includes(target.nodeName) || target.hasAttribute('contentEditable')
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDimensions = (node: HTMLElement): Dimensions => ({
|
export const getDimensions = (node: HTMLElement): Dimensions => ({
|
||||||
@@ -40,40 +48,30 @@ export const getHostForElement = (element: HTMLElement): Document => {
|
|||||||
else return window.document
|
else return window.document
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isEdge = (element: Node | Connection | Edge): element is Edge =>
|
export const isEdge = (element: Node | FlowElement | Connection): element is Edge =>
|
||||||
'id' in element && 'source' in element && 'target' in element
|
'id' in element && 'source' in element && 'target' in element
|
||||||
|
|
||||||
export const isNode = (element: Node | Connection | Edge): element is Node =>
|
export const isNode = (element: Node | FlowElement | Connection): element is Node =>
|
||||||
'id' in element && !('source' in element) && !('target' in element)
|
'id' in element && !('source' in element) && !('target' in element)
|
||||||
|
|
||||||
export const getOutgoers = (node: Node, elements: Elements): Node[] => {
|
export const isGraphNode = (element: Node | FlowElement | Connection): element is GraphNode =>
|
||||||
if (!isNode(node)) {
|
isNode(element) && '__vf' in element
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const outgoerIds = elements.filter((e) => isEdge(e) && e.source === node.id).map((e) => (e as Edge).target)
|
const getConnectedElements = (node: GraphNode, elements: Elements, dir: 'source' | 'target') => {
|
||||||
return elements.filter((e) => outgoerIds.includes(e.id)) as Node[]
|
if (!isNode(node)) return []
|
||||||
|
const ids = elements.filter((e) => isEdge(e) && e.source === node.id).map((e) => isEdge(e) && e[dir])
|
||||||
|
return elements.filter((e) => ids.includes(e.id))
|
||||||
}
|
}
|
||||||
|
export const getOutgoers = (node: GraphNode, elements: Elements) => getConnectedElements(node, elements, 'target')
|
||||||
|
|
||||||
export const getIncomers = (node: Node, elements: Elements): Node[] => {
|
export const getIncomers = (node: GraphNode, elements: Elements) => getConnectedElements(node, elements, 'source')
|
||||||
if (!isNode(node)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const incomersIds = elements.filter((e) => isEdge(e) && e.target === node.id).map((e) => (e as Edge).source)
|
export const removeElements = (elementsToRemove: Elements, elements: Elements) => {
|
||||||
return elements.filter((e) => incomersIds.includes(e.id)) as Node[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removeElements = (elementsToRemove: Elements, elements: Elements): Elements => {
|
|
||||||
const nodeIdsToRemove = elementsToRemove.map((n) => n.id)
|
const nodeIdsToRemove = elementsToRemove.map((n) => n.id)
|
||||||
|
|
||||||
return elements.filter((element) => {
|
return elements.filter((element) => {
|
||||||
const edgeElement = element as Edge
|
const { target, source } = isEdge(element) ? element : { target: '', source: '' }
|
||||||
return !(
|
return !(nodeIdsToRemove.includes(element.id) || nodeIdsToRemove.includes(target) || nodeIdsToRemove.includes(source))
|
||||||
nodeIdsToRemove.includes(element.id) ||
|
|
||||||
nodeIdsToRemove.includes(edgeElement.target) ||
|
|
||||||
nodeIdsToRemove.includes(edgeElement.source)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,13 +89,13 @@ const connectionExists = (edge: Edge, elements: Elements) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elements => {
|
export const addEdge = (edgeParams: Edge | Connection, elements: Elements) => {
|
||||||
if (!edgeParams.source || !edgeParams.target) {
|
if (!edgeParams.source || !edgeParams.target) {
|
||||||
console.log("Can't create edge. An edge needs a source and a target.")
|
console.log("Can't create edge. An edge needs a source and a target.")
|
||||||
return elements
|
return elements
|
||||||
}
|
}
|
||||||
|
|
||||||
let edge: Edge
|
let edge
|
||||||
if (isEdge(edgeParams)) {
|
if (isEdge(edgeParams)) {
|
||||||
edge = { ...edgeParams }
|
edge = { ...edgeParams }
|
||||||
} else {
|
} else {
|
||||||
@@ -114,13 +112,13 @@ export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elem
|
|||||||
return elements.concat(edge)
|
return elements.concat(edge)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: 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.")
|
||||||
return elements
|
return elements
|
||||||
}
|
}
|
||||||
|
|
||||||
const foundEdge = elements.find((e) => isEdge(e) && e.id === oldEdge.id) as Edge
|
const foundEdge = elements.find((e) => isEdge(e) && e.id === oldEdge.id)
|
||||||
|
|
||||||
if (!foundEdge) {
|
if (!foundEdge) {
|
||||||
console.warn(`The old edge with id=${oldEdge.id} does not exist.`)
|
console.warn(`The old edge with id=${oldEdge.id} does not exist.`)
|
||||||
@@ -128,14 +126,14 @@ export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: E
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove old edge and create the new edge with parameters of old edge.
|
// Remove old edge and create the new edge with parameters of old edge.
|
||||||
const edge = {
|
const edge: Edge = {
|
||||||
...oldEdge,
|
...oldEdge,
|
||||||
id: getEdgeId(newConnection),
|
id: getEdgeId(newConnection),
|
||||||
source: newConnection.source,
|
source: newConnection.source,
|
||||||
target: newConnection.target,
|
target: newConnection.target,
|
||||||
sourceHandle: newConnection.sourceHandle,
|
sourceHandle: newConnection.sourceHandle,
|
||||||
targetHandle: newConnection.targetHandle,
|
targetHandle: newConnection.targetHandle,
|
||||||
} as Edge
|
}
|
||||||
|
|
||||||
return elements.filter((e) => e.id !== oldEdge.id).concat(edge)
|
return elements.filter((e) => e.id !== oldEdge.id).concat(edge)
|
||||||
}
|
}
|
||||||
@@ -145,7 +143,7 @@ export const pointToRendererPoint = (
|
|||||||
[tx, ty, tScale]: Transform,
|
[tx, ty, tScale]: Transform,
|
||||||
snapToGrid: boolean,
|
snapToGrid: boolean,
|
||||||
[snapX, snapY]: [number, number],
|
[snapX, snapY]: [number, number],
|
||||||
): XYPosition => {
|
) => {
|
||||||
const position: XYPosition = {
|
const position: XYPosition = {
|
||||||
x: (x - tx) / tScale,
|
x: (x - tx) / tScale,
|
||||||
y: (y - ty) / tScale,
|
y: (y - ty) / tScale,
|
||||||
@@ -161,12 +159,10 @@ export const pointToRendererPoint = (
|
|||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onLoadProject =
|
export const onLoadProject = (currentStore: FlowStore) => (position: XYPosition) =>
|
||||||
(currentStore: FlowStore) =>
|
pointToRendererPoint(position, currentStore.transform, currentStore.snapToGrid, currentStore.snapGrid)
|
||||||
(position: XYPosition): XYPosition =>
|
|
||||||
pointToRendererPoint(position, currentStore.transform, currentStore.snapToGrid, currentStore.snapGrid)
|
|
||||||
|
|
||||||
export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => ({
|
export const parseNode = (node: Node, nodeExtent: NodeExtent): GraphNode => ({
|
||||||
...node,
|
...node,
|
||||||
id: node.id.toString(),
|
id: node.id.toString(),
|
||||||
type: node.type || 'default',
|
type: node.type || 'default',
|
||||||
@@ -174,7 +170,10 @@ export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => ({
|
|||||||
position: clampPosition(node.position, nodeExtent),
|
position: clampPosition(node.position, nodeExtent),
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
handleBounds: {},
|
handleBounds: {
|
||||||
|
source: null,
|
||||||
|
target: null,
|
||||||
|
},
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -210,10 +209,9 @@ export const boxToRect = ({ x, y, x2, y2 }: Box): Rect => ({
|
|||||||
height: y2 - y,
|
height: y2 - y,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getBoundsofRects = (rect1: Rect, rect2: Rect): Rect =>
|
export const getBoundsofRects = (rect1: Rect, rect2: Rect) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)))
|
||||||
boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)))
|
|
||||||
|
|
||||||
export const getRectOfNodes = (nodes: Node[]): Rect => {
|
export const getRectOfNodes = (nodes: GraphNode[]) => {
|
||||||
const box = nodes.reduce(
|
const box = nodes.reduce(
|
||||||
(currBox, { __vf: { position = { x: 0, y: 0 }, width = 0, height = 0 } = {} }) =>
|
(currBox, { __vf: { position = { x: 0, y: 0 }, width = 0, height = 0 } = {} }) =>
|
||||||
getBoundsOfBoxes(
|
getBoundsOfBoxes(
|
||||||
@@ -235,7 +233,7 @@ export const graphPosToZoomedPos = ({ x, y }: XYPosition, [tx, ty, tScale]: Tran
|
|||||||
y: y * tScale + ty,
|
y: y * tScale + ty,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getNodesInside = (nodes: Node[], rect: Rect, [tx, ty, tScale]: Transform = [0, 0, 1], partially = false): Node[] => {
|
export const getNodesInside = (nodes: GraphNode[], rect: Rect, [tx, ty, tScale]: Transform = [0, 0, 1], partially = false) => {
|
||||||
const rBox = rectToBox({
|
const rBox = rectToBox({
|
||||||
x: (rect.x - tx) / tScale,
|
x: (rect.x - tx) / tScale,
|
||||||
y: (rect.y - ty) / tScale,
|
y: (rect.y - ty) / tScale,
|
||||||
@@ -266,13 +264,12 @@ export const getNodesInside = (nodes: Node[], rect: Rect, [tx, ty, tScale]: Tran
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => {
|
export const getConnectedEdges = (nodes: GraphNode[], edges: Edge[]) => {
|
||||||
const nodeIds = nodes.map((node) => node.id)
|
const nodeIds = nodes.map((node) => node.id)
|
||||||
|
|
||||||
return edges.filter((edge) => nodeIds.includes(edge.source) || nodeIds.includes(edge.target))
|
return edges.filter((edge) => nodeIds.includes(edge.source) || nodeIds.includes(edge.target))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onLoadGetElements = (currentStore: FlowStore) => (): Elements => currentStore.elements
|
export const onLoadGetElements = (currentStore: FlowStore) => (): FlowElements => currentStore.elements
|
||||||
|
|
||||||
export const onLoadToObject = (currentStore: FlowStore) => (): FlowExportObject => {
|
export const onLoadToObject = (currentStore: FlowStore) => (): FlowExportObject => {
|
||||||
// we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage
|
// we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
|
export * from './edge'
|
||||||
export * from './graph'
|
export * from './graph'
|
||||||
|
export * from './node'
|
||||||
|
export * from './store'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { HandleElement, Position } from '~/types'
|
import { HandleElement, Position } from '~/types'
|
||||||
import { getDimensions } from '~/utils'
|
import { getDimensions } from '~/utils/graph'
|
||||||
|
|
||||||
export const getHandleBoundsByHandleType = (
|
export const getHandleBoundsByHandleType = (
|
||||||
selector: string,
|
selector: string,
|
||||||
@@ -19,7 +19,7 @@ export const getHandleBoundsByHandleType = (
|
|||||||
const bounds = handle.getBoundingClientRect()
|
const bounds = handle.getBoundingClientRect()
|
||||||
const dimensions = getDimensions(handle)
|
const dimensions = getDimensions(handle)
|
||||||
const handleId = handle.getAttribute('data-handleid')
|
const handleId = handle.getAttribute('data-handleid')
|
||||||
const handlePosition = handle.getAttribute('data-handlepos') as unknown as Position
|
const handlePosition = handle.getAttribute('data-handlepos') as Position
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: handleId,
|
id: handleId,
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
import { Component } from 'vue'
|
import { Component } from 'vue'
|
||||||
import { ConnectionMode, Edge, EdgeProps, Elements, FlowState, Node, NodeExtent, NodeProps, PanOnScrollMode } from '~/types'
|
import { isEdge, isNode, parseEdge, parseNode } from './graph'
|
||||||
import { isEdge, isNode, parseEdge, parseNode } from '~/utils'
|
import {
|
||||||
import { DefaultNode, InputNode, OutputNode } from '~/components/Nodes'
|
ConnectionMode,
|
||||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
Edge,
|
||||||
|
EdgeProps,
|
||||||
|
Elements,
|
||||||
|
FlowState,
|
||||||
|
NextElements,
|
||||||
|
NodeExtent,
|
||||||
|
GraphNode,
|
||||||
|
NodeProps,
|
||||||
|
PanOnScrollMode,
|
||||||
|
} from '~/types'
|
||||||
|
import { DefaultNode, InputNode, OutputNode, BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components'
|
||||||
import { createHooks } from '~/composables'
|
import { createHooks } from '~/composables'
|
||||||
|
|
||||||
export type NextElements = {
|
|
||||||
nextNodes: Node[]
|
|
||||||
nextEdges: Edge[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultNodeTypes: Record<string, Component<NodeProps>> = {
|
export const defaultNodeTypes: Record<string, Component<NodeProps>> = {
|
||||||
input: InputNode,
|
input: InputNode,
|
||||||
default: DefaultNode,
|
default: DefaultNode,
|
||||||
@@ -94,7 +99,7 @@ export const initialState = (): FlowState => ({
|
|||||||
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
|
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const parseElements = async (elements: Elements, nodes: Node[], edges: Edge[], nodeExtent: NodeExtent) =>
|
export const parseElements = async (elements: Elements, nodes: GraphNode[], edges: Edge[], nodeExtent: NodeExtent) =>
|
||||||
new Promise<NextElements>((resolve) => {
|
new Promise<NextElements>((resolve) => {
|
||||||
const nextElements: NextElements = {
|
const nextElements: NextElements = {
|
||||||
nextNodes: [],
|
nextNodes: [],
|
||||||
@@ -105,20 +110,20 @@ export const parseElements = async (elements: Elements, nodes: Node[], edges: Ed
|
|||||||
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
|
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
|
||||||
|
|
||||||
if (storeNode) {
|
if (storeNode) {
|
||||||
const updatedNode: Node = {
|
const updatedNode: GraphNode = {
|
||||||
...storeNode,
|
...storeNode,
|
||||||
...element,
|
...element,
|
||||||
}
|
}
|
||||||
if (!updatedNode.__vf) updatedNode.__vf = {}
|
if (!updatedNode.__vf) updatedNode.__vf = {} as any
|
||||||
|
|
||||||
if (storeNode.position.x !== element.position.x || storeNode.position.y !== element.position.y) {
|
if (storeNode.position.x !== element.position.x || storeNode.position.y !== element.position.y) {
|
||||||
updatedNode.__vf.position = element.position
|
updatedNode.__vf!.position = element.position
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
|
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
|
||||||
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
||||||
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
||||||
updatedNode.__vf.width = undefined
|
updatedNode.__vf!.width = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
nextElements.nextNodes.push(updatedNode)
|
nextElements.nextNodes.push(updatedNode)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Connection, Edge, Elements, Node, NodeExtent, XYPosition } from '~/types'
|
import { Connection, Edge, Elements, Node, NodeExtent, GraphNode, XYPosition, NextElements, FlowElement } from '~/types'
|
||||||
|
|
||||||
export default () =>
|
export default () =>
|
||||||
useWebWorkerFn((elements: Elements, nodes: Node[], edges: Edge[], nodeExtent: NodeExtent) => {
|
useWebWorkerFn((elements: Elements, nodes: GraphNode[], edges: Edge[], nodeExtent: NodeExtent): NextElements => {
|
||||||
const clamp = (val: number, min = 0, max = 1): number => Math.min(Math.max(val, min), max)
|
const clamp = (val: number, min = 0, max = 1): number => Math.min(Math.max(val, min), max)
|
||||||
|
|
||||||
const clampPosition = (position: XYPosition, extent: NodeExtent): XYPosition => ({
|
const clampPosition = (position: XYPosition, extent: NodeExtent): XYPosition => ({
|
||||||
@@ -9,14 +9,14 @@ export default () =>
|
|||||||
y: clamp(position.y, extent[0][1], extent[1][1]),
|
y: clamp(position.y, extent[0][1], extent[1][1]),
|
||||||
})
|
})
|
||||||
|
|
||||||
const parseNode = (node: Node, nodeExtent: NodeExtent): Node =>
|
const parseNode = (node: Node, nodeExtent: NodeExtent): GraphNode =>
|
||||||
Object.assign(node, {
|
Object.assign(node as GraphNode, {
|
||||||
id: node.id.toString(),
|
id: node.id.toString(),
|
||||||
type: node.type || 'default',
|
type: node.type || 'default',
|
||||||
__vf: {
|
__vf: {
|
||||||
position: clampPosition(node.position, nodeExtent),
|
position: clampPosition(node.position, nodeExtent),
|
||||||
width: undefined,
|
width: 0,
|
||||||
height: undefined,
|
height: 0,
|
||||||
handleBounds: {},
|
handleBounds: {},
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
},
|
},
|
||||||
@@ -32,13 +32,13 @@ export default () =>
|
|||||||
type: edge.type || 'default',
|
type: edge.type || 'default',
|
||||||
})
|
})
|
||||||
|
|
||||||
const isEdge = (element: Node | Connection | Edge): element is Edge =>
|
const isEdge = (element: Node | FlowElement | Connection): element is Edge =>
|
||||||
'id' in element && 'source' in element && 'target' in element
|
'id' in element && 'source' in element && 'target' in element
|
||||||
|
|
||||||
const isNode = (element: Node | Connection | Edge): element is Node =>
|
const isNode = (element: Node | FlowElement | Connection): element is Node =>
|
||||||
'id' in element && !('source' in element) && !('target' in element)
|
'id' in element && !('source' in element) && !('target' in element)
|
||||||
|
|
||||||
const nextElements: any = {
|
const nextElements: NextElements = {
|
||||||
nextNodes: [],
|
nextNodes: [],
|
||||||
nextEdges: [],
|
nextEdges: [],
|
||||||
}
|
}
|
||||||
@@ -48,17 +48,17 @@ export default () =>
|
|||||||
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
|
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
|
||||||
|
|
||||||
if (storeNode) {
|
if (storeNode) {
|
||||||
const updatedNode: Node = Object.assign(storeNode, element)
|
const updatedNode = Object.assign(storeNode, element)
|
||||||
if (!updatedNode.__vf) updatedNode.__vf = {}
|
if (!updatedNode.__vf) updatedNode.__vf = {} as any
|
||||||
|
|
||||||
if (storeNode.position.x !== element.position.x || storeNode.position.y !== element.position.y) {
|
if (storeNode.position.x !== element.position.x || storeNode.position.y !== element.position.y) {
|
||||||
updatedNode.__vf.position = element.position
|
updatedNode.__vf!.position = element.position
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
|
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
|
||||||
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
||||||
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
||||||
updatedNode.__vf.width = undefined
|
updatedNode.__vf!.width = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
nextElements.nextNodes.push(updatedNode)
|
nextElements.nextNodes.push(updatedNode)
|
||||||
|
|||||||
Reference in New Issue
Block a user