fix: edges and edge anchors not re-calculating correctly
This commit is contained in:
@@ -13,6 +13,7 @@ import Flow, {
|
|||||||
Position,
|
Position,
|
||||||
SnapGrid,
|
SnapGrid,
|
||||||
Connection,
|
Connection,
|
||||||
|
ConnectionMode,
|
||||||
Edge,
|
Edge,
|
||||||
} from '~/index'
|
} from '~/index'
|
||||||
|
|
||||||
@@ -114,6 +115,7 @@ const onConnect = (params: Connection | Edge) =>
|
|||||||
:elements="elements"
|
:elements="elements"
|
||||||
:style="`background: ${bgColor}`"
|
:style="`background: ${bgColor}`"
|
||||||
:node-types="nodeTypes"
|
:node-types="nodeTypes"
|
||||||
|
:connection-mode="ConnectionMode.Loose"
|
||||||
:connection-line-style="connectionLineStyle"
|
:connection-line-style="connectionLineStyle"
|
||||||
:snap-to-grid="true"
|
:snap-to-grid="true"
|
||||||
:snap-grid="snapGrid"
|
:snap-grid="snapGrid"
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
import EdgeAnchor from './EdgeAnchor.vue'
|
import EdgeAnchor from './EdgeAnchor.vue'
|
||||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils'
|
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils'
|
||||||
import { isEdge } from '~/utils/graph'
|
import { isEdge } from '~/utils/graph'
|
||||||
import { ConnectionMode, Edge, EdgeType, Position } from '~/types'
|
import { ConnectionMode, Edge, EdgeType, HandleElement, Position, EdgePositions } from '~/types'
|
||||||
import { Hooks, Store } from '~/context'
|
import { Hooks, Store } from '~/context'
|
||||||
import { useHandle } from '~/composables'
|
import { useHandle } from '~/composables'
|
||||||
|
|
||||||
interface EdgeProps {
|
interface EdgeProps {
|
||||||
type: EdgeType
|
type: EdgeType
|
||||||
edge: Edge
|
edge: Edge
|
||||||
nodes: ReturnType<typeof getSourceTargetNodes>
|
|
||||||
markerEndId?: string
|
markerEndId?: string
|
||||||
edgeUpdaterRadius?: number
|
edgeUpdaterRadius?: number
|
||||||
}
|
}
|
||||||
@@ -23,27 +22,19 @@ hooks.connect.on((connection) => {
|
|||||||
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
|
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!props.nodes.sourceNode) {
|
const nodes = computed(() => {
|
||||||
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`)
|
const n = getSourceTargetNodes(props.edge, store.nodes)
|
||||||
}
|
|
||||||
|
|
||||||
if (!props.nodes.targetNode) {
|
if (!n.sourceNode) {
|
||||||
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`)
|
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// when connection type is loose we can define all handles as sources
|
if (!n.targetNode) {
|
||||||
const targetNodeHandles =
|
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`)
|
||||||
store.connectionMode === ConnectionMode.Strict
|
}
|
||||||
? props.nodes.targetNode?.__rf.handleBounds.target
|
|
||||||
: props.nodes.targetNode?.__rf.handleBounds.target || props.nodes.targetNode?.__rf.handleBounds.source
|
|
||||||
|
|
||||||
const sourceHandle =
|
return n
|
||||||
props.nodes.sourceNode && getHandle(props.nodes.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null)
|
})
|
||||||
const targetHandle = getHandle(targetNodeHandles, props.edge.targetHandle || null)
|
|
||||||
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom
|
|
||||||
const targetPosition = targetHandle ? targetHandle.position : Position.Top
|
|
||||||
|
|
||||||
const isSelected = store.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false
|
|
||||||
|
|
||||||
const onEdgeClick = (event: MouseEvent) => {
|
const onEdgeClick = (event: MouseEvent) => {
|
||||||
if (store.elementsSelectable) {
|
if (store.elementsSelectable) {
|
||||||
@@ -102,8 +93,30 @@ const isVisible = ({ sourceX, sourceY, targetX, targetY }: ReturnType<typeof get
|
|||||||
: true
|
: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when connection type is loose we can define all handles as sources
|
||||||
|
const targetNodeHandles = computed(() =>
|
||||||
|
store.connectionMode === ConnectionMode.Strict
|
||||||
|
? nodes.value.targetNode?.__rf.handleBounds.target
|
||||||
|
: nodes.value.targetNode?.__rf.handleBounds.target || nodes.value.targetNode?.__rf.handleBounds.source,
|
||||||
|
)
|
||||||
|
|
||||||
|
const sourceHandle = computed(
|
||||||
|
() => nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null),
|
||||||
|
)
|
||||||
|
const targetHandle = computed(() => getHandle(targetNodeHandles.value, props.edge.targetHandle || null))
|
||||||
|
const sourcePosition = computed(() => (sourceHandle.value ? sourceHandle.value.position : Position.Bottom))
|
||||||
|
const targetPosition = computed(() => (targetHandle.value ? targetHandle.value.position : Position.Top))
|
||||||
|
|
||||||
|
const isSelected = computed(() => store.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false)
|
||||||
const edgePos = computed(() =>
|
const edgePos = computed(() =>
|
||||||
getEdgePositions(props.nodes.sourceNode, sourceHandle, sourcePosition, props.nodes.targetNode, targetHandle, targetPosition),
|
getEdgePositions(
|
||||||
|
nodes.value.sourceNode,
|
||||||
|
sourceHandle.value,
|
||||||
|
sourcePosition.value,
|
||||||
|
nodes.value.targetNode,
|
||||||
|
targetHandle.value,
|
||||||
|
targetPosition.value,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ import { pointer, select } from 'd3-selection'
|
|||||||
import { Ref } from 'vue'
|
import { Ref } from 'vue'
|
||||||
import { get } from '@vueuse/core'
|
import { get } from '@vueuse/core'
|
||||||
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
||||||
import { clamp, onLoadGetElements, onLoadProject, onLoadToObject } from '~/utils'
|
import { clamp } from '~/utils'
|
||||||
import useKeyPress from '~/composables/useKeyPress'
|
import useKeyPress from '~/composables/useKeyPress'
|
||||||
import { Hooks, Store } from '~/context'
|
import { Hooks, Store } from '~/context'
|
||||||
import { useZoomPanHelper } from '~/composables/index'
|
|
||||||
|
|
||||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
||||||
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
||||||
@@ -60,17 +59,6 @@ export default function (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZ
|
|||||||
const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom)
|
const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom)
|
||||||
d3z.transform(d3s, updatedTransform)
|
d3z.transform(d3s, updatedTransform)
|
||||||
store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler })
|
store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler })
|
||||||
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper(store)
|
|
||||||
hooks.load.trigger({
|
|
||||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
|
||||||
zoomIn,
|
|
||||||
zoomOut,
|
|
||||||
zoomTo,
|
|
||||||
setTransform,
|
|
||||||
project: onLoadProject(store),
|
|
||||||
getElements: onLoadGetElements(store),
|
|
||||||
toObject: onLoadToObject(store),
|
|
||||||
})
|
|
||||||
|
|
||||||
const applyZoomHandlers = () => {
|
const applyZoomHandlers = () => {
|
||||||
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ const connectionLineVisible = computed(
|
|||||||
<Edge
|
<Edge
|
||||||
v-if="!edge.isHidden"
|
v-if="!edge.isHidden"
|
||||||
:edge="edge"
|
:edge="edge"
|
||||||
:nodes="getSourceTargetNodes(edge, store.nodes)"
|
|
||||||
:type="props.edgeTypes[edge.type || 'default']"
|
:type="props.edgeTypes[edge.type || 'default']"
|
||||||
:marker-end-id="props.markerEndId"
|
:marker-end-id="props.markerEndId"
|
||||||
:edge-updater-radius="props.edgeUpdaterRadius"
|
:edge-updater-radius="props.edgeUpdaterRadius"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
||||||
import { rectToBox } from '~/utils/graph'
|
import { rectToBox } from '~/utils/graph'
|
||||||
import { Edge, EdgeType, ElementId, HandleElement, Node, Position, Transform, XYPosition } from '~/types'
|
import { Edge, EdgePositions, EdgeType, ElementId, HandleElement, Node, Position, Transform, XYPosition } from '~/types'
|
||||||
|
|
||||||
export function createEdgeTypes(edgeTypes: Record<string, EdgeType>): Record<string, EdgeType> {
|
export function createEdgeTypes(edgeTypes: Record<string, EdgeType>): Record<string, EdgeType> {
|
||||||
const standardTypes: Record<string, EdgeType> = {
|
const standardTypes: Record<string, EdgeType> = {
|
||||||
@@ -55,28 +55,19 @@ export function getHandlePosition(position: Position, node: Node, handle: any |
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleElement | null {
|
export function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleElement | undefined {
|
||||||
if (!bounds) {
|
if (!bounds) return undefined
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// there is no handleId when there are no multiple handles/ handles with ids
|
// there is no handleId when there are no multiple handles/ handles with ids
|
||||||
// so we just pick the first one
|
// so we just pick the first one
|
||||||
let handle = null
|
let handle
|
||||||
if (bounds.length === 1 || !handleId) {
|
if (bounds.length === 1 || !handleId) {
|
||||||
handle = bounds[0]
|
handle = bounds[0]
|
||||||
} else if (handleId) {
|
} else if (handleId) {
|
||||||
handle = bounds.find((d) => d.id === handleId)
|
handle = bounds.find((d) => d.id === handleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeof handle === 'undefined' ? null : handle
|
return typeof handle === 'undefined' ? undefined : handle
|
||||||
}
|
|
||||||
|
|
||||||
interface EdgePositions {
|
|
||||||
sourceX: number
|
|
||||||
sourceY: number
|
|
||||||
targetX: number
|
|
||||||
targetY: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getEdgePositions = (
|
export const getEdgePositions = (
|
||||||
|
|||||||
@@ -46,6 +46,17 @@ store.dimensions = {
|
|||||||
width: width.value,
|
width: width.value,
|
||||||
height: height.value,
|
height: height.value,
|
||||||
}
|
}
|
||||||
|
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper()
|
||||||
|
hooks.load.trigger({
|
||||||
|
fitView: (params = { padding: 0.1 }) => fitView(params),
|
||||||
|
zoomIn,
|
||||||
|
zoomOut,
|
||||||
|
zoomTo,
|
||||||
|
setTransform,
|
||||||
|
project: onLoadProject(store),
|
||||||
|
getElements: onLoadGetElements(store),
|
||||||
|
toObject: onLoadToObject(store),
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div ref="zoom-pane" class="revue-flow__renderer revue-flow__zoompane">
|
<div ref="zoom-pane" class="revue-flow__renderer revue-flow__zoompane">
|
||||||
|
|||||||
@@ -56,3 +56,10 @@ export interface EdgeSmoothStepProps<T = any> extends EdgeProps<T> {
|
|||||||
export type EdgeType = DefineComponent<EdgeSmoothStepProps>
|
export type EdgeType = DefineComponent<EdgeSmoothStepProps>
|
||||||
|
|
||||||
export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void
|
export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void
|
||||||
|
|
||||||
|
export interface EdgePositions {
|
||||||
|
sourceX: number
|
||||||
|
sourceY: number
|
||||||
|
targetX: number
|
||||||
|
targetY: number
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user