Skip to content

Commit

Permalink
fix(core): use center position of handle as snapping point for connec…
Browse files Browse the repository at this point in the history
…tion lines (#1625)

* fix(core): calculate handle positions correctly

Signed-off-by: braks <[email protected]>

* fix(core): remove handleId check

Signed-off-by: braks <[email protected]>

* chore(core): cleanup

Signed-off-by: braks <[email protected]>

* chore(core): cleanup click connect handlers

Signed-off-by: braks <[email protected]>

* fix(core): add flow id to handle ids

Signed-off-by: braks <[email protected]>

* tests: correct updateEdge test

Signed-off-by: braks <[email protected]>

* fix(core): use center position of handle

Signed-off-by: braks <[email protected]>

* chore(examples): cleanup easy connect example

Signed-off-by: braks <[email protected]>

* refactor(tests): run actions on chrome

Signed-off-by: braks <[email protected]>

* chore(workflows): correctly hash lock file

Signed-off-by: braks <[email protected]>

---------

Signed-off-by: braks <[email protected]>
  • Loading branch information
bcakmakoglu committed Jan 4, 2025
1 parent 041fd87 commit b33da47
Show file tree
Hide file tree
Showing 16 changed files with 387 additions and 314 deletions.
2 changes: 1 addition & 1 deletion .github/actions/install-dependencies/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ runs:
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,3 @@ jobs:
with:
install-command: pnpm cypress install
command: pnpm run test --cache-dir=.turbo
browser: chrome
component: true
54 changes: 23 additions & 31 deletions examples/vite/src/EasyConnect/EasyConnect.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap'
import type { Elements } from '@vue-flow/core'
import type { Node } from '@vue-flow/core'
import { MarkerType, VueFlow, useVueFlow } from '@vue-flow/core'
import CustomNode from './CustomNode.vue'
import CustomConnectionLine from './CustomConnectionLine.vue'
import FloatingConnectionLine from './FloatingConnectionLine.vue'
import FloatingEdge from './FloatingEdge.vue'
const { onConnect, addEdges } = useVueFlow()
Expand All @@ -20,7 +18,7 @@ const defaultEdgeOptions = {
},
}
const elements = ref<Elements>([
const nodes = ref<Node[]>([
{
id: '1',
type: 'custom',
Expand All @@ -43,37 +41,31 @@ const elements = ref<Elements>([
},
])
const edges = ref([])
onConnect(addEdges)
</script>

<template>
<div style="height: 100vh">
<VueFlow
v-model="elements"
:elevate-nodes-on-select="false"
class="vue-flow-basic-example"
:default-zoom="1.5"
:default-edge-options="defaultEdgeOptions"
:min-zoom="0.2"
:max-zoom="4"
>
<Background pattern-color="#aaa" :gap="8" />

<MiniMap />

<Controls />
<VueFlow
v-model:nodes="nodes"
v-model:edges="edges"
:elevate-nodes-on-select="false"
:default-edge-options="defaultEdgeOptions"
fit-view-on-init
>
<Background pattern-color="#aaa" :gap="8" />

<template #node-custom="props">
<CustomNode :id="props.id" />
</template>
<template #node-custom="props">
<CustomNode :id="props.id" />
</template>

<template #edge-floating="fProps">
<FloatingEdge v-bind="fProps" />
</template>
<template #edge-floating="fProps">
<FloatingEdge v-bind="fProps" />
</template>

<template #connection-line="cProps">
<CustomConnectionLine v-bind="cProps" />
</template>
</VueFlow>
</div>
<template #connection-line="cProps">
<FloatingConnectionLine v-bind="cProps" />
</template>
</VueFlow>
</template>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts" setup>
import type { GraphNode } from '@vue-flow/core'
import { getStraightPath } from '@vue-flow/core'
import type { ConnectionLineProps } from '@vue-flow/core'
import { BaseEdge, getStraightPath } from '@vue-flow/core'
import { computed } from 'vue'
const props = defineProps<{ sourceNode: GraphNode; sourceX: number; sourceY: number; targetX: number; targetY: number }>()
const props = defineProps<ConnectionLineProps>()
const edgePath = computed(() =>
getStraightPath({
Expand All @@ -15,13 +15,12 @@ const edgePath = computed(() =>

<template>
<g>
<path
<BaseEdge
:style="{
strokeWidth: 3,
stroke: 'black',
}"
fill="none"
:d="edgePath[0]"
:path="edgePath[0]"
/>
<circle :cx="targetX" :cy="targetY" fill="black" :r="3" stroke="black" :stroke-width="1.5" />
</g>
Expand Down
8 changes: 4 additions & 4 deletions examples/vite/src/EasyConnect/FloatingEdge.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts" setup>
import type { GraphNode } from '@vue-flow/core'
import { getStraightPath } from '@vue-flow/core'
import type { EdgeProps } from '@vue-flow/core'
import { BaseEdge, getStraightPath } from '@vue-flow/core'
import { computed } from 'vue'
import { getEdgeParams } from './utils'
const props = defineProps<{ id: string; sourceNode: GraphNode; targetNode: GraphNode; markerEnd: string; style: any }>()
const props = defineProps<EdgeProps>()
const edgeParams = computed(() => getEdgeParams(props.sourceNode, props.targetNode))
Expand All @@ -20,5 +20,5 @@ const edgePath = computed(() =>
</script>

<template>
<path :id="id" class="vue-flow__edge-path" :d="edgePath[0]" :marker-end="markerEnd" :style="style" />
<BaseEdge :id="id" :path="edgePath[0]" :marker-end="markerEnd" :style="style" />
</template>
17 changes: 5 additions & 12 deletions packages/core/src/components/ConnectionLine/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { computed, defineComponent, h, inject } from 'vue'
import type { HandleElement } from '../../types'
import { ConnectionLineType, ConnectionMode, Position } from '../../types'
import { getHandlePosition, getMarkerId } from '../../utils'
import { getHandlePosition, getMarkerId, oppositePosition } from '../../utils'
import { useVueFlow } from '../../composables'
import { Slots } from '../../context'
import { getBezierPath, getSimpleBezierPath, getSmoothStepPath } from '../Edges/utils'

const oppositePosition = {
[Position.Left]: Position.Right,
[Position.Right]: Position.Left,
[Position.Top]: Position.Bottom,
[Position.Bottom]: Position.Top,
}

const ConnectionLine = defineComponent({
name: 'ConnectionLine',
compatConfig: { MODE: 3 },
Expand Down Expand Up @@ -57,7 +50,7 @@ const ConnectionLine = defineComponent({
return null
}

const startHandleId = connectionStartHandle.value.handleId
const startHandleId = connectionStartHandle.value.id

const handleType = connectionStartHandle.value.type

Expand All @@ -78,18 +71,18 @@ const ConnectionLine = defineComponent({
const { x: fromX, y: fromY } = getHandlePosition(fromNode.value, fromHandle, fromPosition)

let toHandle: HandleElement | null = null
if (toNode.value && connectionEndHandle.value?.handleId) {
if (toNode.value) {
// if connection mode is strict, we only look for handles of the opposite type
if (connectionMode.value === ConnectionMode.Strict) {
toHandle =
toNode.value.handleBounds[handleType === 'source' ? 'target' : 'source']?.find(
(d) => d.id === connectionEndHandle.value?.handleId,
(d) => d.id === connectionEndHandle.value?.id,
) || null
} else {
// if connection mode is loose, look for the handle in both source and target bounds
toHandle =
[...(toNode.value.handleBounds.source || []), ...(toNode.value.handleBounds.target || [])]?.find(
(d) => d.id === connectionEndHandle.value?.handleId,
(d) => d.id === connectionEndHandle.value?.id,
) || null
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/components/Edges/EdgeWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
ErrorCode,
VueFlowError,
elementSelectionKeys,
getHandle,
getEdgeHandle,
getHandlePosition,
getMarkerId,
} from '../../utils'
Expand Down Expand Up @@ -150,7 +150,7 @@ const EdgeWrapper = defineComponent({
sourceNodeHandles = [...(sourceNode.handleBounds.source || []), ...(sourceNode.handleBounds.target || [])]
}

const sourceHandle = getHandle(sourceNodeHandles, edge.value.sourceHandle)
const sourceHandle = getEdgeHandle(sourceNodeHandles, edge.value.sourceHandle)

let targetNodeHandles
if (connectionMode.value === ConnectionMode.Strict) {
Expand All @@ -159,7 +159,7 @@ const EdgeWrapper = defineComponent({
targetNodeHandles = [...(targetNode.handleBounds.target || []), ...(targetNode.handleBounds.source || [])]
}

const targetHandle = getHandle(targetNodeHandles, edge.value.targetHandle)
const targetHandle = getEdgeHandle(targetNodeHandles, edge.value.targetHandle)

const sourcePosition = sourceHandle?.position || Position.Bottom

Expand Down
11 changes: 7 additions & 4 deletions packages/core/src/components/Handle/Handle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const type = toRef(() => props.type ?? 'source')
const isValidConnection = toRef(() => props.isValidConnection ?? null)
const {
id: flowId,
connectionStartHandle,
connectionClickStartHandle,
connectionEndHandle,
Expand All @@ -39,17 +40,17 @@ const isConnectableEnd = toRef(() => (typeof connectableEnd !== 'undefined' ? co
const isConnecting = toRef(
() =>
(connectionStartHandle.value?.nodeId === nodeId &&
connectionStartHandle.value?.handleId === handleId &&
connectionStartHandle.value?.id === handleId &&
connectionStartHandle.value?.type === type.value) ||
(connectionEndHandle.value?.nodeId === nodeId &&
connectionEndHandle.value?.handleId === handleId &&
connectionEndHandle.value?.id === handleId &&
connectionEndHandle.value?.type === type.value),
)
const isClickConnecting = toRef(
() =>
connectionClickStartHandle.value?.nodeId === nodeId &&
connectionClickStartHandle.value?.handleId === handleId &&
connectionClickStartHandle.value?.id === handleId &&
connectionClickStartHandle.value?.type === type.value,
)
Expand Down Expand Up @@ -127,6 +128,8 @@ onMounted(() => {
position,
x: (handleBounds.left - nodeBounds.left) / zoom,
y: (handleBounds.top - nodeBounds.top) / zoom,
type: type.value,
nodeId,
...getDimensions(handle.value),
}
Expand Down Expand Up @@ -177,7 +180,7 @@ export default {
<template>
<div
ref="handle"
:data-id="`${nodeId}-${handleId}-${type}`"
:data-id="`${flowId}-${nodeId}-${handleId}-${type}`"
:data-handleid="handleId"
:data-nodeid="nodeId"
:data-handlepos="position"
Expand Down
Loading

0 comments on commit b33da47

Please sign in to comment.