feat(edges): hide edge while updating
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import type { CSSProperties, Component, FunctionalComponent, VNode } from 'vue'
|
import type { CSSProperties, Component, VNode } from 'vue'
|
||||||
import EdgeAnchor from './EdgeAnchor'
|
import EdgeAnchor from './EdgeAnchor'
|
||||||
import type { EdgeComponent, EdgeEventsOn, EdgeMarkerType, EdgeTextProps, GraphNode, EdgeUpdatable } from '~/types'
|
import type { EdgeComponent, EdgeEventsOn, EdgeMarkerType, EdgeTextProps, EdgeUpdatable, GraphNode } from '~/types'
|
||||||
import { ConnectionMode, Position } from '~/types'
|
import { ConnectionMode, Position } from '~/types'
|
||||||
import { getEdgePositions, getHandle, getMarkerId } from '~/utils'
|
import { getEdgePositions, getHandle, getMarkerId } from '~/utils'
|
||||||
|
|
||||||
@@ -31,193 +31,178 @@ interface Props {
|
|||||||
markerStart?: EdgeMarkerType
|
markerStart?: EdgeMarkerType
|
||||||
connectionMode: ConnectionMode
|
connectionMode: ConnectionMode
|
||||||
edgeUpdaterRadius: number
|
edgeUpdaterRadius: number
|
||||||
|
updating?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper: FunctionalComponent<Props> = function (
|
const Wrapper = defineComponent({
|
||||||
{
|
props: [
|
||||||
name,
|
'name',
|
||||||
type,
|
'type',
|
||||||
id,
|
'id',
|
||||||
data,
|
'data',
|
||||||
events,
|
'events',
|
||||||
labelBgBorderRadius,
|
'labelBgBorderRadius',
|
||||||
labelBgPadding,
|
'labelBgPadding',
|
||||||
labelBgStyle,
|
'labelBgStyle',
|
||||||
labelStyle,
|
'labelStyle',
|
||||||
labelShowBg,
|
'labelShowBg',
|
||||||
style,
|
'style',
|
||||||
animated,
|
'animated',
|
||||||
label,
|
'label',
|
||||||
updatable,
|
'updatable',
|
||||||
selectable,
|
'selectable',
|
||||||
target,
|
'target',
|
||||||
source,
|
'source',
|
||||||
sourceNode,
|
'sourceNode',
|
||||||
targetNode,
|
'targetNode',
|
||||||
sourceHandleId,
|
'sourceHandleId',
|
||||||
targetHandleId,
|
'targetHandleId',
|
||||||
selected,
|
'selected',
|
||||||
markerEnd,
|
'markerEnd',
|
||||||
markerStart,
|
'markerStart',
|
||||||
connectionMode,
|
'connectionMode',
|
||||||
edgeUpdaterRadius,
|
'edgeUpdaterRadius',
|
||||||
},
|
'updating',
|
||||||
{ emit },
|
],
|
||||||
) {
|
emits: ['source-mousedown', 'target-mousedown'],
|
||||||
if (!sourceNode || !targetNode) return null
|
setup(props: Props, { emit }) {
|
||||||
|
let updating = $ref(false)
|
||||||
|
|
||||||
let updating = $ref(false)
|
const onEdgeUpdaterMouseEnter = () => (updating = true)
|
||||||
|
|
||||||
const onEdgeUpdaterMouseEnter = () => (updating = true)
|
const onEdgeUpdaterMouseOut = () => (updating = false)
|
||||||
|
|
||||||
const onEdgeUpdaterMouseOut = () => (updating = false)
|
const onEdgeUpdaterSourceMouseDown = (e: MouseEvent) => {
|
||||||
|
emit('source-mousedown', e)
|
||||||
|
}
|
||||||
|
|
||||||
const onEdgeUpdaterSourceMouseDown = (e: MouseEvent) => {
|
const onEdgeUpdaterTargetMouseDown = (e: MouseEvent) => {
|
||||||
emit('source-mousedown', e)
|
emit('target-mousedown', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onEdgeUpdaterTargetMouseDown = (e: MouseEvent) => {
|
return () => {
|
||||||
emit('target-mousedown', e)
|
if (!props.sourceNode || !props.targetNode) return null
|
||||||
}
|
|
||||||
|
|
||||||
let sourceNodeHandles
|
let sourceNodeHandles
|
||||||
if (connectionMode === ConnectionMode.Strict) {
|
if (props.connectionMode === ConnectionMode.Strict) {
|
||||||
sourceNodeHandles = sourceNode.handleBounds.source
|
sourceNodeHandles = props.sourceNode.handleBounds.source
|
||||||
} else {
|
} else {
|
||||||
sourceNodeHandles = sourceNode.handleBounds.source ?? sourceNode.handleBounds.target
|
sourceNodeHandles = props.sourceNode.handleBounds.source ?? props.sourceNode.handleBounds.target
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceHandle = getHandle(sourceNodeHandles, sourceHandleId)
|
const sourceHandle = getHandle(sourceNodeHandles, props.sourceHandleId)
|
||||||
|
|
||||||
let targetNodeHandles
|
let targetNodeHandles
|
||||||
if (connectionMode === ConnectionMode.Strict) {
|
if (props.connectionMode === ConnectionMode.Strict) {
|
||||||
targetNodeHandles = targetNode.handleBounds.target
|
targetNodeHandles = props.targetNode.handleBounds.target
|
||||||
} else {
|
} else {
|
||||||
targetNodeHandles = targetNode.handleBounds.target ?? targetNode.handleBounds.source
|
targetNodeHandles = props.targetNode.handleBounds.target ?? props.targetNode.handleBounds.source
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetHandle = getHandle(targetNodeHandles, targetHandleId)
|
const targetHandle = getHandle(targetNodeHandles, props.targetHandleId)
|
||||||
|
|
||||||
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom
|
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom
|
||||||
|
|
||||||
const targetPosition = targetHandle ? targetHandle.position : Position.Top
|
const targetPosition = targetHandle ? targetHandle.position : Position.Top
|
||||||
|
|
||||||
const { sourceX, sourceY, targetY, targetX } = getEdgePositions(
|
const { sourceX, sourceY, targetY, targetX } = getEdgePositions(
|
||||||
sourceNode,
|
props.sourceNode,
|
||||||
sourceHandle,
|
sourceHandle,
|
||||||
sourcePosition,
|
|
||||||
targetNode,
|
|
||||||
targetHandle,
|
|
||||||
targetPosition,
|
|
||||||
)
|
|
||||||
|
|
||||||
return h(
|
|
||||||
'g',
|
|
||||||
{
|
|
||||||
class: [
|
|
||||||
'vue-flow__edge',
|
|
||||||
`vue-flow__edge-${name}`,
|
|
||||||
{
|
|
||||||
updating,
|
|
||||||
selected,
|
|
||||||
animated,
|
|
||||||
inactive: !selectable,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
[
|
|
||||||
h(type as any, {
|
|
||||||
id,
|
|
||||||
sourceNode,
|
|
||||||
targetNode,
|
|
||||||
source,
|
|
||||||
target,
|
|
||||||
updatable,
|
|
||||||
selected,
|
|
||||||
animated,
|
|
||||||
label,
|
|
||||||
labelStyle,
|
|
||||||
labelShowBg,
|
|
||||||
labelBgStyle,
|
|
||||||
labelBgPadding,
|
|
||||||
labelBgBorderRadius,
|
|
||||||
data,
|
|
||||||
events,
|
|
||||||
style,
|
|
||||||
markerStart: `url(#${getMarkerId(markerStart)})`,
|
|
||||||
markerEnd: `url(#${getMarkerId(markerEnd)})`,
|
|
||||||
sourcePosition,
|
sourcePosition,
|
||||||
|
props.targetNode,
|
||||||
|
targetHandle,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
sourceX,
|
)
|
||||||
sourceY,
|
|
||||||
targetX,
|
return h(
|
||||||
targetY,
|
'g',
|
||||||
sourceHandleId,
|
{
|
||||||
targetHandleId,
|
class: [
|
||||||
}),
|
'vue-flow__edge',
|
||||||
[
|
`vue-flow__edge-${props.name}`,
|
||||||
updatable === 'source' || updatable === true ? [ h(
|
|
||||||
'g',
|
|
||||||
{
|
{
|
||||||
onMousedown: onEdgeUpdaterSourceMouseDown,
|
updating,
|
||||||
onMouseenter: onEdgeUpdaterMouseEnter,
|
selected: props.selected,
|
||||||
onMouseout: onEdgeUpdaterMouseOut,
|
animated: props.animated,
|
||||||
|
inactive: !props.selectable,
|
||||||
},
|
},
|
||||||
h(EdgeAnchor, {
|
],
|
||||||
position: sourcePosition,
|
},
|
||||||
centerX: sourceX,
|
[
|
||||||
centerY: sourceY,
|
props.updating
|
||||||
radius: edgeUpdaterRadius,
|
? null
|
||||||
}),
|
: h(props.type as any, {
|
||||||
)] : null,
|
id: props.id,
|
||||||
updatable === 'target' || updatable === true ? [ h(
|
sourceNode: props.sourceNode,
|
||||||
'g',
|
targetNode: props.targetNode,
|
||||||
{
|
source: props.source,
|
||||||
onMousedown: onEdgeUpdaterTargetMouseDown,
|
target: props.target,
|
||||||
onMouseenter: onEdgeUpdaterMouseEnter,
|
updatable: props.updatable,
|
||||||
onMouseout: onEdgeUpdaterMouseOut,
|
selected: props.selected,
|
||||||
},
|
animated: props.animated,
|
||||||
h(EdgeAnchor, {
|
label: props.label,
|
||||||
position: targetPosition,
|
labelStyle: props.labelStyle,
|
||||||
centerX: targetX,
|
labelShowBg: props.labelShowBg,
|
||||||
centerY: targetY,
|
labelBgStyle: props.labelBgStyle,
|
||||||
radius: edgeUpdaterRadius,
|
labelBgPadding: props.labelBgPadding,
|
||||||
}),
|
labelBgBorderRadius: props.labelBgBorderRadius,
|
||||||
)] : null,
|
data: props.data,
|
||||||
|
events: props.events,
|
||||||
|
style: props.style,
|
||||||
|
markerStart: `url(#${getMarkerId(props.markerStart)})`,
|
||||||
|
markerEnd: `url(#${getMarkerId(props.markerEnd)})`,
|
||||||
|
sourcePosition,
|
||||||
|
targetPosition,
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
sourceHandleId: props.sourceHandleId,
|
||||||
|
targetHandleId: props.targetHandleId,
|
||||||
|
}),
|
||||||
|
|
||||||
|
[
|
||||||
|
props.updatable === 'source' || props.updatable === true
|
||||||
|
? [
|
||||||
|
h(
|
||||||
|
'g',
|
||||||
|
{
|
||||||
|
onMousedown: onEdgeUpdaterSourceMouseDown,
|
||||||
|
onMouseenter: onEdgeUpdaterMouseEnter,
|
||||||
|
onMouseout: onEdgeUpdaterMouseOut,
|
||||||
|
},
|
||||||
|
h(EdgeAnchor, {
|
||||||
|
position: sourcePosition,
|
||||||
|
centerX: sourceX,
|
||||||
|
centerY: sourceY,
|
||||||
|
radius: props.edgeUpdaterRadius,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null,
|
||||||
|
props.updatable === 'target' || props.updatable === true
|
||||||
|
? [
|
||||||
|
h(
|
||||||
|
'g',
|
||||||
|
{
|
||||||
|
onMousedown: onEdgeUpdaterTargetMouseDown,
|
||||||
|
onMouseenter: onEdgeUpdaterMouseEnter,
|
||||||
|
onMouseout: onEdgeUpdaterMouseOut,
|
||||||
|
},
|
||||||
|
h(EdgeAnchor, {
|
||||||
|
position: targetPosition,
|
||||||
|
centerX: targetX,
|
||||||
|
centerY: targetY,
|
||||||
|
radius: props.edgeUpdaterRadius,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
)
|
||||||
)
|
}
|
||||||
}
|
},
|
||||||
|
})
|
||||||
Wrapper.props = [
|
|
||||||
'name',
|
|
||||||
'type',
|
|
||||||
'id',
|
|
||||||
'data',
|
|
||||||
'events',
|
|
||||||
'labelBgBorderRadius',
|
|
||||||
'labelBgPadding',
|
|
||||||
'labelBgStyle',
|
|
||||||
'labelStyle',
|
|
||||||
'labelShowBg',
|
|
||||||
'style',
|
|
||||||
'animated',
|
|
||||||
'label',
|
|
||||||
'updatable',
|
|
||||||
'selectable',
|
|
||||||
'target',
|
|
||||||
'source',
|
|
||||||
'sourceNode',
|
|
||||||
'targetNode',
|
|
||||||
'sourceHandleId',
|
|
||||||
'targetHandleId',
|
|
||||||
'selected',
|
|
||||||
'markerEnd',
|
|
||||||
'markerStart',
|
|
||||||
'connectionMode',
|
|
||||||
'edgeUpdaterRadius',
|
|
||||||
]
|
|
||||||
|
|
||||||
Wrapper.emits = ['source-mousedown', 'target-mousedown']
|
|
||||||
|
|
||||||
export default Wrapper
|
export default Wrapper
|
||||||
|
|||||||
@@ -32,8 +32,11 @@ const {
|
|||||||
} = $(useVueFlow())
|
} = $(useVueFlow())
|
||||||
|
|
||||||
const selectable = (s?: boolean) => (typeof s === 'undefined' ? elementsSelectable : s)
|
const selectable = (s?: boolean) => (typeof s === 'undefined' ? elementsSelectable : s)
|
||||||
|
|
||||||
const updatable = (u?: EdgeUpdatable) => (typeof u === 'undefined' ? edgesUpdatable : u)
|
const updatable = (u?: EdgeUpdatable) => (typeof u === 'undefined' ? edgesUpdatable : u)
|
||||||
|
|
||||||
|
const updating = ref<string>()
|
||||||
|
|
||||||
const sourceNode = $(
|
const sourceNode = $(
|
||||||
controlledComputed($$(connectionNodeId), () => {
|
controlledComputed($$(connectionNodeId), () => {
|
||||||
if (connectionNodeId) return getNode(connectionNodeId)
|
if (connectionNodeId) return getNode(connectionNodeId)
|
||||||
@@ -142,9 +145,15 @@ const onEdgeMouseMove = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].e
|
|||||||
|
|
||||||
const onEdgeMouseLeave = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.mouseLeave({ event, edge })
|
const onEdgeMouseLeave = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.mouseLeave({ event, edge })
|
||||||
|
|
||||||
const onEdgeUpdaterSourceMouseDown = (event: MouseEvent, edge: GraphEdge) => handleEdgeUpdater(event, edge, true)
|
const onEdgeUpdaterSourceMouseDown = (event: MouseEvent, edge: GraphEdge) => {
|
||||||
|
updating.value = edge.id
|
||||||
|
handleEdgeUpdater(event, edge, true)
|
||||||
|
}
|
||||||
|
|
||||||
const onEdgeUpdaterTargetMouseDown = (event: MouseEvent, edge: GraphEdge) => handleEdgeUpdater(event, edge, false)
|
const onEdgeUpdaterTargetMouseDown = (event: MouseEvent, edge: GraphEdge) => {
|
||||||
|
updating.value = edge.id
|
||||||
|
handleEdgeUpdater(event, edge, false)
|
||||||
|
}
|
||||||
|
|
||||||
const { onMouseDown } = useHandle()
|
const { onMouseDown } = useHandle()
|
||||||
|
|
||||||
@@ -164,7 +173,10 @@ const handleEdgeUpdater = (event: MouseEvent, edge: GraphEdge, isSourceHandle: b
|
|||||||
(connection) => {
|
(connection) => {
|
||||||
if (!connectionExists(connection, getEdges)) hooks[edge.id].emit.update({ edge, connection })
|
if (!connectionExists(connection, getEdges)) hooks[edge.id].emit.update({ edge, connection })
|
||||||
},
|
},
|
||||||
() => hooks[edge.id].emit.updateEnd({ event, edge }),
|
() => {
|
||||||
|
hooks[edge.id].emit.updateEnd({ event, edge })
|
||||||
|
updating.value = ''
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +217,7 @@ export default {
|
|||||||
:selectable="selectable(edge.selectable)"
|
:selectable="selectable(edge.selectable)"
|
||||||
:selected="edge.selected"
|
:selected="edge.selected"
|
||||||
:updatable="updatable(edge.updatable)"
|
:updatable="updatable(edge.updatable)"
|
||||||
|
:updating="edge.id === updating"
|
||||||
:label-style="edge.labelStyle"
|
:label-style="edge.labelStyle"
|
||||||
:label-show-bg="edge.labelShowBg"
|
:label-show-bg="edge.labelShowBg"
|
||||||
:label-bg-style="edge.labelBgStyle"
|
:label-bg-style="edge.labelBgStyle"
|
||||||
|
|||||||
Reference in New Issue
Block a user