182 lines
6.0 KiB
TypeScript
182 lines
6.0 KiB
TypeScript
import { ref, defineComponent, CSSProperties, PropType, computed } from 'vue-demi';
|
|
|
|
import { getBezierPath } from '../Edges/BezierEdge';
|
|
import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
|
|
import {
|
|
ElementId,
|
|
Node,
|
|
Transform,
|
|
HandleElement,
|
|
Position,
|
|
ConnectionLineType,
|
|
ConnectionLineComponent,
|
|
HandleType
|
|
} from '../../types';
|
|
|
|
interface ConnectionLineProps {
|
|
connectionNodeId: ElementId;
|
|
connectionHandleId: ElementId | null;
|
|
connectionHandleType: HandleType;
|
|
connectionPositionX: number;
|
|
connectionPositionY: number;
|
|
connectionLineType: ConnectionLineType;
|
|
nodes: Node[];
|
|
transform: Transform;
|
|
isConnectable: boolean;
|
|
connectionLineStyle?: CSSProperties;
|
|
CustomConnectionLineComponent?: ConnectionLineComponent;
|
|
}
|
|
|
|
const ConnectionLine = defineComponent({
|
|
props: {
|
|
connectionNodeId: {
|
|
type: String as PropType<ConnectionLineProps['connectionNodeId']>,
|
|
required: true
|
|
},
|
|
connectionHandleId: {
|
|
type: String as PropType<ConnectionLineProps['connectionHandleId']>,
|
|
required: true
|
|
},
|
|
connectionHandleType: {
|
|
type: String as PropType<ConnectionLineProps['connectionHandleType']>,
|
|
required: true
|
|
},
|
|
connectionLineStyle: {
|
|
type: Object as PropType<ConnectionLineProps['connectionLineStyle']>,
|
|
required: false,
|
|
default: () => ({})
|
|
},
|
|
connectionPositionX: {
|
|
type: Number as PropType<ConnectionLineProps['connectionPositionX']>,
|
|
required: false,
|
|
default: 0
|
|
},
|
|
connectionPositionY: {
|
|
type: Number as PropType<ConnectionLineProps['connectionPositionY']>,
|
|
required: false,
|
|
default: 0
|
|
},
|
|
connectionLineType: {
|
|
type: String as PropType<ConnectionLineProps['connectionLineType']>,
|
|
required: false,
|
|
default: ConnectionLineType.Bezier
|
|
},
|
|
nodes: {
|
|
type: Array as PropType<ConnectionLineProps['nodes']>,
|
|
required: true,
|
|
default: () => []
|
|
},
|
|
transform: {
|
|
type: Object as PropType<ConnectionLineProps['transform']>,
|
|
required: false,
|
|
default: () => ({})
|
|
},
|
|
isConnectable: {
|
|
type: Boolean as PropType<ConnectionLineProps['isConnectable']>,
|
|
required: false,
|
|
default: false
|
|
},
|
|
CustomConnectionLineComponent: {
|
|
type: Object as PropType<ConnectionLineProps['CustomConnectionLineComponent']>,
|
|
required: false,
|
|
default: undefined
|
|
}
|
|
},
|
|
setup(props) {
|
|
const sourceNode = ref<Node | null>(props.nodes.find((n) => n.id === props.connectionNodeId) || null);
|
|
|
|
if (!sourceNode.value || !props.isConnectable) {
|
|
return null;
|
|
}
|
|
|
|
const sourceHandle = computed(() =>
|
|
props.connectionHandleId
|
|
? sourceNode.value?.__rf.handleBounds[props.connectionHandleType].find(
|
|
(d: HandleElement) => d.id === props.connectionHandleId
|
|
)
|
|
: sourceNode.value?.__rf.handleBounds[props.connectionHandleType][0]
|
|
);
|
|
const sourceHandleX = computed(() =>
|
|
sourceHandle.value ? sourceHandle.value.x + sourceHandle.value.width / 2 : sourceNode.value?.__rf.width / 2
|
|
);
|
|
const sourceHandleY = computed(() =>
|
|
sourceHandle.value ? sourceHandle.value.y + sourceHandle.value.height / 2 : sourceNode.value?.__rf.height
|
|
);
|
|
const sourceX = computed(() => sourceNode.value?.__rf.position.x + sourceHandleX.value);
|
|
const sourceY = computed(() => sourceNode.value?.__rf.position.y + sourceHandleY.value);
|
|
|
|
const targetX = computed(() => (props.connectionPositionX - props.transform[0]) / props.transform[2]);
|
|
const targetY = computed(() => (props.connectionPositionY - props.transform[1]) / props.transform[2]);
|
|
|
|
const isRightOrLeft = computed(
|
|
() => sourceHandle.value?.position === Position.Left || sourceHandle.value?.position === Position.Right
|
|
);
|
|
const targetPosition = computed(() => (isRightOrLeft.value ? Position.Left : Position.Top));
|
|
|
|
if (props.CustomConnectionLineComponent) {
|
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
|
const ConnectionLineComponent: any = props.CustomConnectionLineComponent;
|
|
return () => (
|
|
<g class="react-flow__connection">
|
|
<ConnectionLineComponent
|
|
sourceX={sourceX.value}
|
|
sourceY={sourceY.value}
|
|
sourcePosition={sourceHandle.value?.position}
|
|
targetX={targetX.value}
|
|
targetY={targetY.value}
|
|
targetPosition={targetPosition.value}
|
|
connectionLineType={props.connectionLineType}
|
|
connectionLineStyle={props.connectionLineStyle}
|
|
/>
|
|
</g>
|
|
);
|
|
}
|
|
|
|
let dAttr = computed(() => `M${sourceX.value},${sourceY.value} ${targetX.value},${targetY.value}`);
|
|
|
|
if (props.connectionLineType === ConnectionLineType.Bezier) {
|
|
dAttr = computed(() =>
|
|
getBezierPath({
|
|
sourceX: sourceX.value,
|
|
sourceY: sourceY.value,
|
|
sourcePosition: sourceHandle.value?.position,
|
|
targetX: targetX.value,
|
|
targetY: targetY.value,
|
|
targetPosition: targetPosition.value
|
|
})
|
|
);
|
|
} else if (props.connectionLineType === ConnectionLineType.Step) {
|
|
dAttr = computed(() =>
|
|
getSmoothStepPath({
|
|
sourceX: sourceX.value,
|
|
sourceY: sourceY.value,
|
|
sourcePosition: sourceHandle.value?.position,
|
|
targetX: targetX.value,
|
|
targetY: targetY.value,
|
|
targetPosition: targetPosition.value,
|
|
borderRadius: 0
|
|
})
|
|
);
|
|
} else if (props.connectionLineType === ConnectionLineType.SmoothStep) {
|
|
dAttr = computed(() =>
|
|
getSmoothStepPath({
|
|
sourceX: sourceX.value,
|
|
sourceY: sourceY.value,
|
|
sourcePosition: sourceHandle.value?.position,
|
|
targetX: targetX.value,
|
|
targetY: targetY.value,
|
|
targetPosition: targetPosition.value
|
|
})
|
|
);
|
|
}
|
|
|
|
return () => (
|
|
<g class="react-flow__connection">
|
|
<path d={dAttr.value} class="react-flow__connection-path" style={props.connectionLineStyle} />
|
|
</g>
|
|
);
|
|
}
|
|
});
|
|
|
|
export default ConnectionLine;
|