feat: Add SimpleBezierEdge
* Implement base edge
This commit is contained in:
@@ -10,7 +10,7 @@ const {
|
||||
zoomOnPinch,
|
||||
panOnScroll,
|
||||
panOnScrollMode,
|
||||
paneMovable,
|
||||
panOnDrag,
|
||||
onConnect,
|
||||
onNodeDragStart,
|
||||
onNodeDragStop,
|
||||
@@ -102,7 +102,7 @@ onMoveEnd((flowTransform) => console.log('move end', flowTransform))
|
||||
<div>
|
||||
<label for="panemoveable">
|
||||
paneMovable
|
||||
<input id="panemoveable" v-model="paneMovable" type="checkbox" class="vue-flow__panemoveable" />
|
||||
<input id="panemoveable" v-model="panOnDrag" type="checkbox" class="vue-flow__panemoveable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<script lang="ts" setup>
|
||||
import { Position } from '../../types/flow'
|
||||
import type { EdgeProps } from '../../types/edge'
|
||||
import { getSimpleBezierPath, getSimpleBezierCenter } from './utils'
|
||||
import BaseEdge from './BaseEdge.vue'
|
||||
|
||||
const props = withDefaults(defineProps<EdgeProps>(), {
|
||||
selected: false,
|
||||
sourcePosition: 'bottom' as Position,
|
||||
targetPosition: 'top' as Position,
|
||||
labelStyle: () => ({}),
|
||||
label: () => '',
|
||||
labelShowBg: true,
|
||||
labelBgStyle: () => ({}),
|
||||
})
|
||||
|
||||
const centered = computed(() =>
|
||||
getSimpleBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const path = computed(() => {
|
||||
if (props.sourceX && props.sourceY)
|
||||
return getSimpleBezierCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition,
|
||||
})
|
||||
else return ''
|
||||
})
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SimpleBezierEdge',
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<BaseEdge
|
||||
:path="path"
|
||||
:center-x="centered[0]"
|
||||
:center-y="centered[1]"
|
||||
:label="props.label"
|
||||
:label-style="props.labelStyle"
|
||||
:label-show-bg="props.labelShowBg"
|
||||
:label-bg-style="props.labelBgStyle"
|
||||
:label-bg-padding="props.labelBgPadding"
|
||||
:label-bg-border-radius="props.labelBgBorderRadius"
|
||||
:style="props.style"
|
||||
:marker-end="props.markerEnd"
|
||||
:marker-start="props.markerStart"
|
||||
/>
|
||||
</template>
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Position } from '../../types'
|
||||
import type { SmoothStepEdgeProps } from '../../types/edge'
|
||||
import { getCenter, getSmoothStepPath } from './utils'
|
||||
import EdgeText from './EdgeText.vue'
|
||||
import BaseEdge from './BaseEdge.vue'
|
||||
|
||||
const props = withDefaults(defineProps<SmoothStepEdgeProps>(), {
|
||||
selected: false,
|
||||
@@ -16,14 +16,25 @@ const props = withDefaults(defineProps<SmoothStepEdgeProps>(), {
|
||||
|
||||
const centered = computed(() =>
|
||||
getCenter({
|
||||
...props,
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
|
||||
const path = computed(() => {
|
||||
if (props.sourceX && props.sourceY)
|
||||
return getSmoothStepPath({
|
||||
...props,
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition,
|
||||
borderRadius: props.borderRadius,
|
||||
})
|
||||
else return ''
|
||||
})
|
||||
@@ -31,28 +42,21 @@ const path = computed(() => {
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SmoothStepEdge',
|
||||
inheritAttrs: false,
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<path
|
||||
class="vue-flow__edge-path"
|
||||
<BaseEdge
|
||||
:path="path"
|
||||
:center-x="centered[0]"
|
||||
:center-y="centered[1]"
|
||||
:label="props.label"
|
||||
:label-style="props.labelStyle"
|
||||
:label-show-bg="props.labelShowBg"
|
||||
:label-bg-style="props.labelBgStyle"
|
||||
:label-bg-padding="props.labelBgPadding"
|
||||
:label-bg-border-radius="props.labelBgBorderRadius"
|
||||
:style="props.style"
|
||||
:d="path"
|
||||
:marker-end="props.markerEnd"
|
||||
:marker-start="props.markerStart"
|
||||
/>
|
||||
<slot :x="centered[0]" :y="centered[1]" v-bind="props">
|
||||
<EdgeText
|
||||
v-if="props.label"
|
||||
:x="centered[0]"
|
||||
:y="centered[1]"
|
||||
:label="props.label"
|
||||
:label-style="props.labelStyle"
|
||||
:label-show-bg="props.labelShowBg"
|
||||
:label-bg-style="props.labelBgStyle"
|
||||
:label-bg-padding="props.labelBgPadding"
|
||||
:label-bg-border-radius="props.labelBgBorderRadius"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
@@ -19,7 +19,5 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<SmoothStepEdge v-bind="props" :border-radius="0">
|
||||
<slot />
|
||||
</SmoothStepEdge>
|
||||
<SmoothStepEdge v-bind="props" :border-radius="0" />
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { Position } from '../../types'
|
||||
import type { EdgeProps } from '../../types/edge'
|
||||
import EdgeText from './EdgeText.vue'
|
||||
import { getBezierPath } from './utils'
|
||||
import BaseEdge from './BaseEdge.vue'
|
||||
|
||||
const props = withDefaults(defineProps<EdgeProps>(), {
|
||||
selected: false,
|
||||
@@ -23,39 +22,26 @@ const centerX = computed(() => {
|
||||
return props.targetX < props.sourceX ? props.targetX + xOffset : props.targetX - xOffset
|
||||
})
|
||||
|
||||
const path = computed(() => {
|
||||
if (props.sourceX && props.sourceY)
|
||||
return getBezierPath({
|
||||
...props,
|
||||
})
|
||||
else return ''
|
||||
})
|
||||
const path = computed(() => `M ${props.sourceX},${props.sourceY}L ${props.targetX},${props.targetY}`)
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'StraightEdge',
|
||||
inheritAttrs: false,
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<path
|
||||
class="vue-flow__edge-path"
|
||||
<BaseEdge
|
||||
:path="path"
|
||||
:center-x="centered[0]"
|
||||
:center-y="centered[1]"
|
||||
:label="props.label"
|
||||
:label-style="props.labelStyle"
|
||||
:label-show-bg="props.labelShowBg"
|
||||
:label-bg-style="props.labelBgStyle"
|
||||
:label-bg-padding="props.labelBgPadding"
|
||||
:label-bg-border-radius="props.labelBgBorderRadius"
|
||||
:style="props.style"
|
||||
:d="path"
|
||||
:marker-end="props.markerEnd"
|
||||
:marker-start="props.markerStart"
|
||||
/>
|
||||
<slot :x="centerX" :y="centerY" v-bind="props">
|
||||
<EdgeText
|
||||
v-if="props.label"
|
||||
:x="centerX"
|
||||
:y="centerY"
|
||||
:label="props.label"
|
||||
:label-style="props.labelStyle"
|
||||
:label-show-bg="props.labelShowBg"
|
||||
:label-bg-style="props.labelBgStyle"
|
||||
:label-bg-padding="props.labelBgPadding"
|
||||
:label-bg-border-radius="props.labelBgBorderRadius"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export { default as BezierEdge } from './BezierEdge.vue'
|
||||
export { default as SimpleBezierEdge } from './SimpleBezierEdge.vue'
|
||||
export { default as StepEdge } from './StepEdge.vue'
|
||||
export { default as SmoothStepEdge } from './SmoothStepEdge.vue'
|
||||
export { default as StraightEdge } from './StraightEdge.vue'
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import { Position } from '~/types'
|
||||
|
||||
interface GetControlWithCurvatureParams {
|
||||
pos: Position
|
||||
x1: number
|
||||
y1: number
|
||||
x2: number
|
||||
y2: number
|
||||
c: number
|
||||
}
|
||||
|
||||
export interface GetBezierPathParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
curvature?: number
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
|
||||
function calculateControlOffset(distance: number, curvature: number): number {
|
||||
if (distance >= 0) {
|
||||
return 0.5 * distance
|
||||
} else {
|
||||
return curvature * 25 * Math.sqrt(-distance)
|
||||
}
|
||||
}
|
||||
|
||||
function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurvatureParams): [number, number] {
|
||||
let ctX: number, ctY: number
|
||||
switch (pos) {
|
||||
case Position.Left:
|
||||
ctX = x1 - calculateControlOffset(x1 - x2, c)
|
||||
ctY = y1
|
||||
break
|
||||
case Position.Right:
|
||||
ctX = x1 + calculateControlOffset(x2 - x1, c)
|
||||
ctY = y1
|
||||
break
|
||||
case Position.Top:
|
||||
ctX = x1
|
||||
ctY = y1 - calculateControlOffset(y1 - y2, c)
|
||||
break
|
||||
case Position.Bottom:
|
||||
ctX = x1
|
||||
ctY = y1 + calculateControlOffset(y2 - y1, c)
|
||||
break
|
||||
}
|
||||
return [ctX, ctY]
|
||||
}
|
||||
|
||||
export function getBezierPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
curvature = 0.25,
|
||||
}: GetBezierPathParams): string {
|
||||
const [sourceControlX, sourceControlY] = getControlWithCurvature({
|
||||
pos: sourcePosition,
|
||||
x1: sourceX,
|
||||
y1: sourceY,
|
||||
x2: targetX,
|
||||
y2: targetY,
|
||||
c: curvature,
|
||||
})
|
||||
const [targetControlX, targetControlY] = getControlWithCurvature({
|
||||
pos: targetPosition,
|
||||
x1: targetX,
|
||||
y1: targetY,
|
||||
x2: sourceX,
|
||||
y2: sourceY,
|
||||
c: curvature,
|
||||
})
|
||||
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`
|
||||
}
|
||||
|
||||
export function getBezierCenter({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
curvature = 0.25,
|
||||
}: GetBezierPathParams): [number, number, number, number] {
|
||||
const [sourceControlX, sourceControlY] = getControlWithCurvature({
|
||||
pos: sourcePosition,
|
||||
x1: sourceX,
|
||||
y1: sourceY,
|
||||
x2: targetX,
|
||||
y2: targetY,
|
||||
c: curvature,
|
||||
})
|
||||
const [targetControlX, targetControlY] = getControlWithCurvature({
|
||||
pos: targetPosition,
|
||||
x1: targetX,
|
||||
y1: targetY,
|
||||
x2: sourceX,
|
||||
y2: sourceY,
|
||||
c: curvature,
|
||||
})
|
||||
// cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
|
||||
// https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
|
||||
const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125
|
||||
const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125
|
||||
const xOffset = Math.abs(centerX - sourceX)
|
||||
const yOffset = Math.abs(centerY - sourceY)
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Position } from '~/types'
|
||||
|
||||
export interface GetCenterParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition?: Position
|
||||
targetPosition?: Position
|
||||
}
|
||||
|
||||
const LeftOrRight = [Position.Left, Position.Right]
|
||||
|
||||
export const getCenter = ({
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetPosition = Position.Top,
|
||||
}: GetCenterParams): [number, number, number, number] => {
|
||||
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition)
|
||||
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition)
|
||||
|
||||
// we expect flows to be horizontal or vertical (all handles left or right respectively top or bottom)
|
||||
// a mixed edge is when one the source is on the left and the target is on the top for example.
|
||||
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight)
|
||||
|
||||
if (mixedEdge) {
|
||||
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0
|
||||
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset
|
||||
|
||||
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY)
|
||||
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset
|
||||
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
|
||||
const xOffset = Math.abs(targetX - sourceX) / 2
|
||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset
|
||||
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset
|
||||
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './bezier'
|
||||
export * from './simple-bezier'
|
||||
export * from './smoothstep'
|
||||
export * from './general'
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Position } from '~/types'
|
||||
|
||||
export interface GetSimpleBezierPathParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
}
|
||||
|
||||
interface GetControlParams {
|
||||
pos: Position
|
||||
x1: number
|
||||
y1: number
|
||||
x2: number
|
||||
y2: number
|
||||
}
|
||||
|
||||
function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] {
|
||||
let ctX: number, ctY: number
|
||||
switch (pos) {
|
||||
case Position.Left:
|
||||
case Position.Right:
|
||||
ctX = 0.5 * (x1 + x2)
|
||||
ctY = y1
|
||||
break
|
||||
case Position.Top:
|
||||
case Position.Bottom:
|
||||
ctX = x1
|
||||
ctY = 0.5 * (y1 + y2)
|
||||
break
|
||||
}
|
||||
return [ctX, ctY]
|
||||
}
|
||||
|
||||
export function getSimpleBezierPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
}: GetSimpleBezierPathParams): string {
|
||||
const [sourceControlX, sourceControlY] = getControl({
|
||||
pos: sourcePosition,
|
||||
x1: sourceX,
|
||||
y1: sourceY,
|
||||
x2: targetX,
|
||||
y2: targetY,
|
||||
})
|
||||
const [targetControlX, targetControlY] = getControl({
|
||||
pos: targetPosition,
|
||||
x1: targetX,
|
||||
y1: targetY,
|
||||
x2: sourceX,
|
||||
y2: sourceY,
|
||||
})
|
||||
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`
|
||||
}
|
||||
|
||||
// @TODO: this function will recalculate the control points
|
||||
// one option is to let getXXXPath() return center points
|
||||
// but will introduce breaking changes
|
||||
// the getCenter() of other types of edges might need to change, too
|
||||
export function getSimpleBezierCenter({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
}: GetSimpleBezierPathParams): [number, number, number, number] {
|
||||
const [sourceControlX, sourceControlY] = getControl({
|
||||
pos: sourcePosition,
|
||||
x1: sourceX,
|
||||
y1: sourceY,
|
||||
x2: targetX,
|
||||
y2: targetY,
|
||||
})
|
||||
const [targetControlX, targetControlY] = getControl({
|
||||
pos: targetPosition,
|
||||
x1: targetX,
|
||||
y1: targetY,
|
||||
x2: sourceX,
|
||||
y2: sourceY,
|
||||
})
|
||||
// cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
|
||||
// https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
|
||||
const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125
|
||||
const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125
|
||||
const xOffset = Math.abs(centerX - sourceX)
|
||||
const yOffset = Math.abs(centerY - sourceY)
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
@@ -1,132 +1,16 @@
|
||||
import { GetBezierPathParams, GetCenterParams, GetControlWithCurvatureParams, GetSmoothStepPathParams, Position } from '~/types'
|
||||
import { getCenter } from './general'
|
||||
import { Position } from '~/types'
|
||||
|
||||
const LeftOrRight = [Position.Left, Position.Right]
|
||||
|
||||
export const getCenter = ({
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetPosition = Position.Top,
|
||||
}: GetCenterParams): [number, number, number, number] => {
|
||||
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition)
|
||||
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition)
|
||||
|
||||
// we expect flows to be horizontal or vertical (all handles left or right respectively top or bottom)
|
||||
// a mixed edge is when one the source is on the left and the target is on the top for example.
|
||||
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight)
|
||||
|
||||
if (mixedEdge) {
|
||||
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0
|
||||
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset
|
||||
|
||||
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY)
|
||||
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset
|
||||
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
|
||||
const xOffset = Math.abs(targetX - sourceX) / 2
|
||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset
|
||||
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset
|
||||
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
|
||||
function calculateControlOffset(distance: number, curvature: number): number {
|
||||
if (distance >= 0) {
|
||||
return 0.5 * distance
|
||||
} else {
|
||||
return curvature * 25 * Math.sqrt(-distance)
|
||||
}
|
||||
}
|
||||
|
||||
function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurvatureParams): [number, number] {
|
||||
let ctX: number, ctY: number
|
||||
switch (pos) {
|
||||
case Position.Left:
|
||||
ctX = x1 - calculateControlOffset(x1 - x2, c)
|
||||
ctY = y1
|
||||
break
|
||||
case Position.Right:
|
||||
ctX = x1 + calculateControlOffset(x2 - x1, c)
|
||||
ctY = y1
|
||||
break
|
||||
case Position.Top:
|
||||
ctX = x1
|
||||
ctY = y1 - calculateControlOffset(y1 - y2, c)
|
||||
break
|
||||
case Position.Bottom:
|
||||
ctX = x1
|
||||
ctY = y1 + calculateControlOffset(y2 - y1, c)
|
||||
break
|
||||
}
|
||||
return [ctX, ctY]
|
||||
}
|
||||
|
||||
export function getBezierPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
curvature = 0.25,
|
||||
}: GetBezierPathParams): string {
|
||||
const [sourceControlX, sourceControlY] = getControlWithCurvature({
|
||||
pos: sourcePosition,
|
||||
x1: sourceX,
|
||||
y1: sourceY,
|
||||
x2: targetX,
|
||||
y2: targetY,
|
||||
c: curvature,
|
||||
})
|
||||
const [targetControlX, targetControlY] = getControlWithCurvature({
|
||||
pos: targetPosition,
|
||||
x1: targetX,
|
||||
y1: targetY,
|
||||
x2: sourceX,
|
||||
y2: sourceY,
|
||||
c: curvature,
|
||||
})
|
||||
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`
|
||||
}
|
||||
|
||||
export function getBezierCenter({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
curvature = 0.25,
|
||||
}: GetBezierPathParams): [number, number, number, number] {
|
||||
const [sourceControlX, sourceControlY] = getControlWithCurvature({
|
||||
pos: sourcePosition,
|
||||
x1: sourceX,
|
||||
y1: sourceY,
|
||||
x2: targetX,
|
||||
y2: targetY,
|
||||
c: curvature,
|
||||
})
|
||||
const [targetControlX, targetControlY] = getControlWithCurvature({
|
||||
pos: targetPosition,
|
||||
x1: targetX,
|
||||
y1: targetY,
|
||||
x2: sourceX,
|
||||
y2: sourceY,
|
||||
c: curvature,
|
||||
})
|
||||
// cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
|
||||
// https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
|
||||
const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125
|
||||
const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125
|
||||
const xOffset = Math.abs(centerX - sourceX)
|
||||
const yOffset = Math.abs(centerY - sourceY)
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
export interface GetSmoothStepPathParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
borderRadius?: number
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
|
||||
// These are some helper methods for drawing the round corners
|
||||
+13
-1
@@ -1,7 +1,19 @@
|
||||
export { default as VueFlow } from './container/VueFlow/VueFlow.vue'
|
||||
export { default as Handle } from './components/Handle/Handle.vue'
|
||||
export { default as EdgeText } from './components/Edges/EdgeText.vue'
|
||||
export { getBezierPath, getSmoothStepPath, getCenter as getEdgeCenter, getBezierCenter } from './components/Edges/utils'
|
||||
export { default as StraightEdge } from './components/Edges/StraightEdge.vue'
|
||||
export { default as StepEdge } from './components/Edges/StepEdge.vue'
|
||||
export { default as BezierEdge } from './components/Edges/BezierEdge.vue'
|
||||
export { default as SimpleBezierEdge } from './components/Edges/SimpleBezierEdge.vue'
|
||||
export { default as SmoothStepEdge } from './components/Edges/SmoothStepEdge.vue'
|
||||
export {
|
||||
getBezierPath,
|
||||
getBezierCenter,
|
||||
getSimpleBezierPath,
|
||||
getSimpleBezierCenter,
|
||||
getSmoothStepPath,
|
||||
getCenter as getEdgeCenter,
|
||||
} from './components/Edges/utils'
|
||||
|
||||
export {
|
||||
isNode,
|
||||
|
||||
+11
-1
@@ -8,7 +8,16 @@ import {
|
||||
ConnectionLineType,
|
||||
FlowOptions,
|
||||
} from '~/types'
|
||||
import { DefaultNode, InputNode, OutputNode, BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components'
|
||||
import {
|
||||
DefaultNode,
|
||||
InputNode,
|
||||
OutputNode,
|
||||
BezierEdge,
|
||||
SmoothStepEdge,
|
||||
StepEdge,
|
||||
StraightEdge,
|
||||
SimpleBezierEdge,
|
||||
} from '~/components'
|
||||
|
||||
export const defaultNodeTypes: DefaultNodeTypes = {
|
||||
input: InputNode,
|
||||
@@ -21,6 +30,7 @@ export const defaultEdgeTypes: DefaultEdgeTypes = {
|
||||
straight: StraightEdge,
|
||||
step: StepEdge,
|
||||
smoothstep: SmoothStepEdge,
|
||||
simplebezier: SimpleBezierEdge,
|
||||
}
|
||||
|
||||
const isDef = <T>(val: T): val is NonNullable<T> => typeof val !== 'undefined'
|
||||
|
||||
@@ -19,7 +19,7 @@ export type EdgeComponent<E = any> =
|
||||
| DefineComponent<EdgeProps<E>, any, any, any, any, any>
|
||||
| GlobalComponentName
|
||||
|
||||
export type DefaultEdgeTypes = { [key in 'default' | 'straight' | 'smoothstep' | 'step']: EdgeComponent }
|
||||
export type DefaultEdgeTypes = { [key in 'default' | 'straight' | 'smoothstep' | 'step' | 'simplebezier']: EdgeComponent }
|
||||
export type DefaultNodeTypes = { [key in 'input' | 'output' | 'default']: NodeComponent }
|
||||
|
||||
export interface BackgroundProps {
|
||||
|
||||
@@ -168,45 +168,3 @@ export interface SmoothStepEdgeProps<Data = any> extends EdgeProps<Data> {
|
||||
markerEnd?: string
|
||||
borderRadius?: number
|
||||
}
|
||||
|
||||
export interface GetCenterParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition?: Position
|
||||
targetPosition?: Position
|
||||
}
|
||||
|
||||
export interface GetBezierPathParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
curvature?: number
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
|
||||
export interface GetSmoothStepPathParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
borderRadius?: number
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
|
||||
export interface GetControlWithCurvatureParams {
|
||||
pos: Position
|
||||
x1: number
|
||||
y1: number
|
||||
x2: number
|
||||
y2: number
|
||||
c: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user