feat: Transform react-flow to vue-jsx
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
import { CSSProperties, defineComponent, PropType } from 'vue';
|
||||
|
||||
import EdgeText from './EdgeText';
|
||||
|
||||
import { getMarkerEnd, getCenter } from './utils';
|
||||
import { ArrowHeadType, Position } from '../../types';
|
||||
|
||||
interface GetBezierPathParams {
|
||||
sourceX: number;
|
||||
sourceY: number;
|
||||
sourcePosition?: Position;
|
||||
targetX: number;
|
||||
targetY: number;
|
||||
targetPosition?: Position;
|
||||
centerX?: number;
|
||||
centerY?: number;
|
||||
}
|
||||
|
||||
export function getBezierPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
centerX,
|
||||
centerY
|
||||
}: GetBezierPathParams): string {
|
||||
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||
const leftAndRight = [Position.Left, Position.Right];
|
||||
|
||||
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
|
||||
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
|
||||
|
||||
let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`;
|
||||
|
||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`;
|
||||
} else if (leftAndRight.includes(targetPosition)) {
|
||||
path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
||||
} else if (leftAndRight.includes(sourcePosition)) {
|
||||
path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const BezierEdge = defineComponent({
|
||||
props: {
|
||||
sourceX: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
sourceY: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
targetX: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
targetY: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0
|
||||
},
|
||||
sourcePosition: {
|
||||
type: String as PropType<Position>,
|
||||
required: true,
|
||||
default: Position.Bottom
|
||||
},
|
||||
targetPosition: {
|
||||
type: String as PropType<Position>,
|
||||
required: true,
|
||||
default: Position.Top
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
labelStyle: {
|
||||
type: Object as PropType<any>,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
},
|
||||
labelShowBg: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
labelBgStyle: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
labelBgPadding: {
|
||||
type: ([0, 0] as any) as PropType<[number, number]>,
|
||||
required: false,
|
||||
default: () => [0, 0] as [number, number]
|
||||
},
|
||||
labelBgBorderRadius: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
arrowHeadType: {
|
||||
type: Object as PropType<ArrowHeadType>,
|
||||
required: true
|
||||
},
|
||||
markerEndId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
style: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
required: false,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const [centerX, centerY] = getCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition
|
||||
});
|
||||
const path = getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition
|
||||
});
|
||||
|
||||
const text = props.label ? (
|
||||
<EdgeText
|
||||
x={centerX}
|
||||
y={centerY}
|
||||
label={props.label}
|
||||
labelStyle={props.labelStyle}
|
||||
labelShowBg={props.labelShowBg}
|
||||
labelBgStyle={props.labelBgStyle}
|
||||
labelBgPadding={props.labelBgPadding}
|
||||
labelBgBorderRadius={props.labelBgBorderRadius}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
const markerEnd = getMarkerEnd(props.arrowHeadType, props.markerEndId);
|
||||
|
||||
return (
|
||||
<>
|
||||
<path style={props.style} d={path} class="react-flow__edge-path" marker-end={markerEnd} />
|
||||
{text}
|
||||
</>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default BezierEdge;
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Position } from '../../types';
|
||||
import { defineComponent, HTMLAttributes, PropType } from 'vue';
|
||||
|
||||
const shiftX = (x: number, shift: number, position: Position): number => {
|
||||
if (position === Position.Left) return x - shift;
|
||||
if (position === Position.Right) return x + shift;
|
||||
return x;
|
||||
};
|
||||
|
||||
const shiftY = (y: number, shift: number, position: Position): number => {
|
||||
if (position === Position.Top) return y - shift;
|
||||
if (position === Position.Bottom) return y + shift;
|
||||
return y;
|
||||
};
|
||||
|
||||
export interface EdgeAnchorProps extends HTMLAttributes {
|
||||
position: Position;
|
||||
centerX: number;
|
||||
centerY: number;
|
||||
radius?: number;
|
||||
}
|
||||
|
||||
export const EdgeAnchor = defineComponent({
|
||||
props: {
|
||||
position: {
|
||||
type: String as PropType<EdgeAnchorProps['position']>,
|
||||
required: true
|
||||
},
|
||||
centerX: {
|
||||
type: Number as PropType<EdgeAnchorProps['centerX']>,
|
||||
required: true
|
||||
},
|
||||
centerY: {
|
||||
type: Number as PropType<EdgeAnchorProps['centerY']>,
|
||||
required: true
|
||||
},
|
||||
radius: {
|
||||
type: Number as PropType<EdgeAnchorProps['radius']>,
|
||||
required: false,
|
||||
default: 10
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const radius = props.radius || 10;
|
||||
return () => (
|
||||
<circle
|
||||
class="react-flow__edgeupdater"
|
||||
cx={shiftX(props.centerX, radius, props.position)}
|
||||
cy={shiftY(props.centerY, radius, props.position)}
|
||||
r={radius}
|
||||
stroke="transparent"
|
||||
fill="transparent"
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
import { EdgeTextProps, Rect } from '../../types';
|
||||
import { defineComponent, PropType, ref, watch } from 'vue';
|
||||
|
||||
const EdgeText = defineComponent({
|
||||
props: {
|
||||
x: {
|
||||
type: Number as PropType<EdgeTextProps['x']>,
|
||||
required: true
|
||||
},
|
||||
y: {
|
||||
type: Number as PropType<EdgeTextProps['y']>,
|
||||
required: true
|
||||
},
|
||||
label: {
|
||||
type: String as PropType<EdgeTextProps['label']>,
|
||||
required: true
|
||||
},
|
||||
labelStyle: {
|
||||
type: Object as PropType<EdgeTextProps['labelStyle']>,
|
||||
default: () => ({})
|
||||
},
|
||||
labelShowBg: {
|
||||
type: Boolean as PropType<EdgeTextProps['labelShowBg']>,
|
||||
default: true
|
||||
},
|
||||
labelBgStyle: {
|
||||
type: Object as PropType<EdgeTextProps['labelBgStyle']>,
|
||||
default: () => ({})
|
||||
},
|
||||
labelBgPadding: {
|
||||
/* @ts-ignore */
|
||||
type: Array as PropType<[number, number]>,
|
||||
default: () => [2, 4]
|
||||
},
|
||||
labelBgBorderRadius: {
|
||||
type: Number as PropType<EdgeTextProps['labelBgBorderRadius']>,
|
||||
default: 2
|
||||
}
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const edgeRef = ref<SVGTextElement | null>(null);
|
||||
const edgeTextBox = ref<Rect>({ x: 0, y: 0, width: 0, height: 0 });
|
||||
const label = ref(props.label);
|
||||
|
||||
watch(label, () => {
|
||||
if (edgeRef.value) {
|
||||
const textBbox = edgeRef.value.getBBox();
|
||||
|
||||
edgeRef.value = {
|
||||
x: textBbox.x,
|
||||
y: textBbox.y,
|
||||
width: textBbox.width,
|
||||
height: textBbox.height
|
||||
} as any;
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof label.value === 'undefined' || !label.value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<g
|
||||
transform={`translate(${props.x - edgeTextBox.value.width / 2} ${props.y - edgeTextBox.value.height / 2})`}
|
||||
class="react-flow__edge-textwrapper"
|
||||
>
|
||||
{props.labelShowBg && (
|
||||
<rect
|
||||
width={edgeTextBox.value.width + 2 * props.labelBgPadding[0]}
|
||||
x={-props.labelBgPadding[0]}
|
||||
y={-props.labelBgPadding[1]}
|
||||
height={edgeTextBox.value.height + 2 * props.labelBgPadding[1]}
|
||||
class="react-flow__edge-textbg"
|
||||
style={props.labelBgStyle}
|
||||
rx={props.labelBgBorderRadius}
|
||||
ry={props.labelBgBorderRadius}
|
||||
/>
|
||||
)}
|
||||
<text class="react-flow__edge-text" y={edgeTextBox.value.height / 2} dy="0.3em" ref={edgeRef} style={props.labelStyle}>
|
||||
{label}
|
||||
</text>
|
||||
{slots.default ? slots.default() : ''}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default EdgeText;
|
||||
@@ -0,0 +1,141 @@
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import EdgeText from './EdgeText';
|
||||
import { getMarkerEnd, getCenter } from './utils';
|
||||
import { EdgeSmoothStepProps, Position } from '../../types';
|
||||
|
||||
// These are some helper methods for drawing the round corners
|
||||
// The name indicates the direction of the path. "bottomLeftCorner" goes
|
||||
// from bottom to the left and "leftBottomCorner" goes from left to the bottom.
|
||||
// We have to consider the direction of the paths because of the animated lines.
|
||||
const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}`;
|
||||
const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}`;
|
||||
const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}`;
|
||||
const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}`;
|
||||
const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}`;
|
||||
const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}`;
|
||||
const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}`;
|
||||
const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}`;
|
||||
|
||||
interface GetSmoothStepPathParams {
|
||||
sourceX: number;
|
||||
sourceY: number;
|
||||
sourcePosition?: Position;
|
||||
targetX: number;
|
||||
targetY: number;
|
||||
targetPosition?: Position;
|
||||
borderRadius?: number;
|
||||
centerX?: number;
|
||||
centerY?: number;
|
||||
}
|
||||
|
||||
export function getSmoothStepPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
sourcePosition = Position.Bottom,
|
||||
targetX,
|
||||
targetY,
|
||||
targetPosition = Position.Top,
|
||||
borderRadius = 5,
|
||||
centerX,
|
||||
centerY
|
||||
}: GetSmoothStepPathParams): string {
|
||||
const [_centerX, _centerY, offsetX, offsetY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX));
|
||||
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY));
|
||||
const cornerSize = Math.min(cornerWidth, cornerHeight, offsetX, offsetY);
|
||||
const leftAndRight = [Position.Left, Position.Right];
|
||||
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
|
||||
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
|
||||
|
||||
let firstCornerPath;
|
||||
let secondCornerPath;
|
||||
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath = sourceY <= targetY ? bottomLeftCorner(sourceX, cY, cornerSize) : topLeftCorner(sourceX, cY, cornerSize);
|
||||
secondCornerPath = sourceY <= targetY ? rightTopCorner(targetX, cY, cornerSize) : rightBottomCorner(targetX, cY, cornerSize);
|
||||
} else {
|
||||
firstCornerPath = sourceY < targetY ? bottomRightCorner(sourceX, cY, cornerSize) : topRightCorner(sourceX, cY, cornerSize);
|
||||
secondCornerPath = sourceY < targetY ? leftTopCorner(targetX, cY, cornerSize) : leftBottomCorner(targetX, cY, cornerSize);
|
||||
}
|
||||
|
||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath = sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize);
|
||||
secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize);
|
||||
} else if (sourcePosition === Position.Right && targetPosition === Position.Left) {
|
||||
// and sourceX > targetX
|
||||
firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize);
|
||||
secondCornerPath =
|
||||
sourceY <= targetY ? bottomRightCorner(cX, targetY, cornerSize) : topRightCorner(cX, targetY, cornerSize);
|
||||
}
|
||||
} else if (leftAndRight.includes(sourcePosition) && !leftAndRight.includes(targetPosition)) {
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? rightTopCorner(targetX, sourceY, cornerSize) : rightBottomCorner(targetX, sourceY, cornerSize);
|
||||
} else {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? leftTopCorner(targetX, sourceY, cornerSize) : leftBottomCorner(targetX, sourceY, cornerSize);
|
||||
}
|
||||
secondCornerPath = '';
|
||||
} else if (!leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? bottomLeftCorner(sourceX, targetY, cornerSize) : topLeftCorner(sourceX, targetY, cornerSize);
|
||||
} else {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? bottomRightCorner(sourceX, targetY, cornerSize) : topRightCorner(sourceX, targetY, cornerSize);
|
||||
}
|
||||
secondCornerPath = '';
|
||||
}
|
||||
|
||||
return `M ${sourceX},${sourceY}${firstCornerPath}${secondCornerPath}L ${targetX},${targetY}`;
|
||||
}
|
||||
|
||||
const SmoothStepEdge = defineComponent({
|
||||
props: EdgeSmoothStepProps,
|
||||
setup(props) {
|
||||
const [centerX, centerY] = getCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition
|
||||
});
|
||||
|
||||
const path = getSmoothStepPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetPosition: props.targetPosition,
|
||||
borderRadius: props.borderRadius
|
||||
});
|
||||
|
||||
const markerEnd = getMarkerEnd(props.arrowHeadType, props.markerEndId);
|
||||
|
||||
const text = props.label ? (
|
||||
<EdgeText
|
||||
x={centerX}
|
||||
y={centerY}
|
||||
label={props.label}
|
||||
labelStyle={props.labelStyle}
|
||||
labelShowBg={props.labelShowBg}
|
||||
labelBgStyle={props.labelBgStyle}
|
||||
labelBgPadding={props.labelBgPadding}
|
||||
labelBgBorderRadius={props.labelBgBorderRadius}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<path style={props.style} class="react-flow__edge-path" d={path} marker-end={markerEnd} />
|
||||
{text}
|
||||
</>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default SmoothStepEdge;
|
||||
@@ -0,0 +1,14 @@
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import { EdgeSmoothStepProps } from '../../types';
|
||||
import SmoothStepEdge from './SmoothStepEdge';
|
||||
|
||||
const StepEdge = defineComponent({
|
||||
components: { SmoothStepEdge },
|
||||
props: EdgeSmoothStepProps,
|
||||
setup(props) {
|
||||
return () => <SmoothStepEdge {...props} borderRadius={0} />;
|
||||
}
|
||||
});
|
||||
|
||||
export default StepEdge;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import EdgeText from './EdgeText';
|
||||
import { getMarkerEnd } from './utils';
|
||||
import { EdgeProps } from '../../types';
|
||||
|
||||
const StraightEdge = defineComponent({
|
||||
props: EdgeProps,
|
||||
setup(props) {
|
||||
const yOffset = Math.abs(props.targetY - props.sourceY) / 2;
|
||||
const centerY = props.targetY < props.sourceY ? props.targetY + yOffset : props.targetY - yOffset;
|
||||
|
||||
const xOffset = Math.abs(props.targetX - props.sourceX) / 2;
|
||||
const centerX = props.targetX < props.sourceX ? props.targetX + xOffset : props.targetX - xOffset;
|
||||
const markerEnd = getMarkerEnd(props.arrowHeadType, props.markerEndId);
|
||||
|
||||
const text = props.label ? (
|
||||
<EdgeText
|
||||
x={centerX}
|
||||
y={centerY}
|
||||
label={props.label}
|
||||
labelStyle={props.labelStyle}
|
||||
labelShowBg={props.labelShowBg}
|
||||
labelBgStyle={props.labelBgStyle}
|
||||
labelBgPadding={props.labelBgPadding}
|
||||
labelBgBorderRadius={props.labelBgBorderRadius}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
style={props.style}
|
||||
class="react-flow__edge-path"
|
||||
d={`M ${props.sourceX},${props.sourceY}L ${props.targetX},${props.targetY}`}
|
||||
marker-end={markerEnd}
|
||||
/>
|
||||
{text}
|
||||
</>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default StraightEdge;
|
||||
@@ -0,0 +1,4 @@
|
||||
export { default as BezierEdge } from './BezierEdge';
|
||||
export { default as StepEdge } from './StepEdge';
|
||||
export { default as SmoothStepEdge } from './SmoothStepEdge';
|
||||
export { default as StraightEdge } from './StraightEdge';
|
||||
@@ -0,0 +1,54 @@
|
||||
import { ArrowHeadType, Position } from '../../types';
|
||||
|
||||
export const getMarkerEnd = (arrowHeadType?: ArrowHeadType, markerEndId?: string): string => {
|
||||
if (typeof markerEndId !== 'undefined' && markerEndId) {
|
||||
return `url(#${markerEndId})`;
|
||||
}
|
||||
|
||||
return typeof arrowHeadType !== 'undefined' ? `url(#react-flow__${arrowHeadType})` : 'none';
|
||||
};
|
||||
|
||||
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,183 @@
|
||||
import { Component, computed, defineComponent, ref } from 'vue';
|
||||
|
||||
import store from '../../store';
|
||||
import { Edge, EdgeProps, Position, WrapEdgeProps } from '../../types';
|
||||
import { onMouseDown } from '../Handle/handler';
|
||||
import { EdgeAnchor } from './EdgeAnchor';
|
||||
|
||||
export default (EdgeComponent: any): Component<EdgeProps> => {
|
||||
return defineComponent({
|
||||
components: { EdgeComponent },
|
||||
props: WrapEdgeProps,
|
||||
setup(props) {
|
||||
console.log('wrap');
|
||||
const pinia = store();
|
||||
|
||||
const updating = ref<boolean>(false);
|
||||
|
||||
const inactive = !props.elementsSelectable && !props.onClick;
|
||||
const edgeClasses = [
|
||||
'react-flow__edge',
|
||||
`react-flow__edge-${props.type}`,
|
||||
{ selected: props.selected, animated: props.animated, inactive, updating }
|
||||
];
|
||||
|
||||
const edgeElement = computed<Edge>(() => {
|
||||
const el: Edge = {
|
||||
id: props.id || '',
|
||||
source: props.source || '',
|
||||
target: props.target || '',
|
||||
type: props.type
|
||||
};
|
||||
|
||||
if (props.sourceHandleId) {
|
||||
el.sourceHandle = props.sourceHandleId;
|
||||
}
|
||||
|
||||
if (props.targetHandleId) {
|
||||
el.targetHandle = props.targetHandleId;
|
||||
}
|
||||
|
||||
if (typeof props.data !== 'undefined') {
|
||||
el.data = props.data;
|
||||
}
|
||||
|
||||
return el;
|
||||
});
|
||||
|
||||
const onEdgeClick = (event: MouseEvent) => {
|
||||
if (props.elementsSelectable) {
|
||||
pinia.unsetNodesSelection();
|
||||
pinia.addSelectedElements(edgeElement.value as any);
|
||||
}
|
||||
|
||||
props.onClick?.(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeContextMenu = (event: MouseEvent) => {
|
||||
props.onContextMenu?.(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeMouseEnter = (event: MouseEvent) => {
|
||||
props.onMouseEnter?.(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeMouseMove = (event: MouseEvent) => {
|
||||
props.onMouseMove?.(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeMouseLeave = (event: MouseEvent) => {
|
||||
props.onMouseLeave?.(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const handleEdgeUpdater = (event: MouseEvent, isSourceHandle: boolean) => {
|
||||
const nodeId = isSourceHandle ? props.target : props.source;
|
||||
const handleId = isSourceHandle ? props.targetHandleId : props.sourceHandleId;
|
||||
const isValidConnection = () => true;
|
||||
const isTarget = isSourceHandle;
|
||||
|
||||
props.onEdgeUpdateStart?.(event, edgeElement.value);
|
||||
|
||||
const _onEdgeUpdate = props.onEdgeUpdateEnd
|
||||
? (evt: MouseEvent) => {
|
||||
if (props.onEdgeUpdateEnd) props.onEdgeUpdateEnd(evt, edgeElement.value);
|
||||
}
|
||||
: undefined;
|
||||
|
||||
onMouseDown(
|
||||
event,
|
||||
handleId,
|
||||
nodeId || '',
|
||||
pinia.setConnectionNodeId,
|
||||
pinia.setConnectionPosition,
|
||||
props.onConnectEdge,
|
||||
isTarget,
|
||||
isValidConnection,
|
||||
pinia.connectionMode,
|
||||
isSourceHandle ? 'target' : 'source',
|
||||
_onEdgeUpdate
|
||||
);
|
||||
};
|
||||
|
||||
const onEdgeUpdaterSourceMouseDown = (event: MouseEvent) => {
|
||||
handleEdgeUpdater(event, true);
|
||||
};
|
||||
|
||||
const onEdgeUpdaterTargetMouseDown = (event: MouseEvent) => {
|
||||
handleEdgeUpdater(event, false);
|
||||
};
|
||||
|
||||
const onEdgeUpdaterMouseEnter = () => (updating.value = true);
|
||||
const onEdgeUpdaterMouseOut = () => (updating.value = false);
|
||||
|
||||
if (props.isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return () => (
|
||||
<g
|
||||
class={edgeClasses}
|
||||
onClick={onEdgeClick}
|
||||
onContextmenu={onEdgeContextMenu}
|
||||
onMouseenter={onEdgeMouseEnter}
|
||||
onMousemove={onEdgeMouseMove}
|
||||
onMouseleave={onEdgeMouseLeave}
|
||||
>
|
||||
<EdgeComponent
|
||||
id={props.id}
|
||||
source={props.source}
|
||||
target={props.target}
|
||||
selected={props.selected}
|
||||
animated={props.animated}
|
||||
label={props.label}
|
||||
labelStyle={props.labelStyle}
|
||||
labelShowBg={props.labelShowBg}
|
||||
labelBgStyle={props.labelBgStyle}
|
||||
labelBgPadding={props.labelBgPadding}
|
||||
labelBgBorderRadius={props.labelBgBorderRadius}
|
||||
data={props.data}
|
||||
style={props.style}
|
||||
arrowHeadType={props.arrowHeadType}
|
||||
sourceX={props.sourceX}
|
||||
sourceY={props.sourceY}
|
||||
targetX={props.targetX}
|
||||
targetY={props.targetY}
|
||||
sourcePosition={props.sourcePosition}
|
||||
targetPosition={props.targetPosition}
|
||||
markerEndId={props.markerEndId}
|
||||
sourceHandleId={props.sourceHandleId}
|
||||
targetHandleId={props.targetHandleId}
|
||||
/>
|
||||
{props.handleEdgeUpdate && (
|
||||
<g
|
||||
onMousedown={onEdgeUpdaterSourceMouseDown}
|
||||
onMouseenter={onEdgeUpdaterMouseEnter}
|
||||
onMouseout={onEdgeUpdaterMouseOut}
|
||||
>
|
||||
<EdgeAnchor
|
||||
position={props.sourcePosition as Position}
|
||||
centerX={props.sourceX as number}
|
||||
centerY={props.sourceY as number}
|
||||
radius={props.edgeUpdaterRadius}
|
||||
/>
|
||||
</g>
|
||||
)}
|
||||
{props.handleEdgeUpdate && (
|
||||
<g
|
||||
onMousedown={onEdgeUpdaterTargetMouseDown}
|
||||
onMouseenter={onEdgeUpdaterMouseEnter}
|
||||
onMouseout={onEdgeUpdaterMouseOut}
|
||||
>
|
||||
<EdgeAnchor
|
||||
position={props.sourcePosition as Position}
|
||||
centerX={props.sourceX as number}
|
||||
centerY={props.sourceY as number}
|
||||
radius={props.edgeUpdaterRadius}
|
||||
/>
|
||||
</g>
|
||||
)}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user