fix: edges and edge anchors not re-calculating correctly
This commit is contained in:
@@ -13,6 +13,7 @@ import Flow, {
|
||||
Position,
|
||||
SnapGrid,
|
||||
Connection,
|
||||
ConnectionMode,
|
||||
Edge,
|
||||
} from '~/index'
|
||||
|
||||
@@ -114,6 +115,7 @@ const onConnect = (params: Connection | Edge) =>
|
||||
:elements="elements"
|
||||
:style="`background: ${bgColor}`"
|
||||
:node-types="nodeTypes"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
:connection-line-style="connectionLineStyle"
|
||||
:snap-to-grid="true"
|
||||
:snap-grid="snapGrid"
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
import EdgeAnchor from './EdgeAnchor.vue'
|
||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils'
|
||||
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 { useHandle } from '~/composables'
|
||||
|
||||
interface EdgeProps {
|
||||
type: EdgeType
|
||||
edge: Edge
|
||||
nodes: ReturnType<typeof getSourceTargetNodes>
|
||||
markerEndId?: string
|
||||
edgeUpdaterRadius?: number
|
||||
}
|
||||
@@ -23,27 +22,19 @@ hooks.connect.on((connection) => {
|
||||
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
|
||||
})
|
||||
|
||||
if (!props.nodes.sourceNode) {
|
||||
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`)
|
||||
}
|
||||
const nodes = computed(() => {
|
||||
const n = getSourceTargetNodes(props.edge, store.nodes)
|
||||
|
||||
if (!props.nodes.targetNode) {
|
||||
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`)
|
||||
}
|
||||
if (!n.sourceNode) {
|
||||
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
|
||||
const targetNodeHandles =
|
||||
store.connectionMode === ConnectionMode.Strict
|
||||
? props.nodes.targetNode?.__rf.handleBounds.target
|
||||
: props.nodes.targetNode?.__rf.handleBounds.target || props.nodes.targetNode?.__rf.handleBounds.source
|
||||
if (!n.targetNode) {
|
||||
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`)
|
||||
}
|
||||
|
||||
const sourceHandle =
|
||||
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
|
||||
return n
|
||||
})
|
||||
|
||||
const onEdgeClick = (event: MouseEvent) => {
|
||||
if (store.elementsSelectable) {
|
||||
@@ -102,8 +93,30 @@ const isVisible = ({ sourceX, sourceY, targetX, targetY }: ReturnType<typeof get
|
||||
: 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(() =>
|
||||
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>
|
||||
<template>
|
||||
|
||||
@@ -3,10 +3,9 @@ import { pointer, select } from 'd3-selection'
|
||||
import { Ref } from 'vue'
|
||||
import { get } from '@vueuse/core'
|
||||
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 { Hooks, Store } from '~/context'
|
||||
import { useZoomPanHelper } from '~/composables/index'
|
||||
|
||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
||||
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)
|
||||
d3z.transform(d3s, updatedTransform)
|
||||
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 = () => {
|
||||
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||
|
||||
@@ -39,7 +39,6 @@ const connectionLineVisible = computed(
|
||||
<Edge
|
||||
v-if="!edge.isHidden"
|
||||
:edge="edge"
|
||||
:nodes="getSourceTargetNodes(edge, store.nodes)"
|
||||
:type="props.edgeTypes[edge.type || 'default']"
|
||||
:marker-end-id="props.markerEndId"
|
||||
:edge-updater-radius="props.edgeUpdaterRadius"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
||||
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> {
|
||||
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 {
|
||||
if (!bounds) {
|
||||
return null
|
||||
}
|
||||
export function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleElement | undefined {
|
||||
if (!bounds) return undefined
|
||||
|
||||
// there is no handleId when there are no multiple handles/ handles with ids
|
||||
// so we just pick the first one
|
||||
let handle = null
|
||||
let handle
|
||||
if (bounds.length === 1 || !handleId) {
|
||||
handle = bounds[0]
|
||||
} else if (handleId) {
|
||||
handle = bounds.find((d) => d.id === handleId)
|
||||
}
|
||||
|
||||
return typeof handle === 'undefined' ? null : handle
|
||||
}
|
||||
|
||||
interface EdgePositions {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
return typeof handle === 'undefined' ? undefined : handle
|
||||
}
|
||||
|
||||
export const getEdgePositions = (
|
||||
|
||||
@@ -46,6 +46,17 @@ store.dimensions = {
|
||||
width: width.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>
|
||||
<template>
|
||||
<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 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