@@ -15,6 +15,7 @@ React Flow is a library for building node-based graphs. You can easily implement
|
|||||||
- [Edges](#edges)
|
- [Edges](#edges)
|
||||||
- [Options](#options)
|
- [Options](#options)
|
||||||
- [Edge Types & Custom Edges](#edge-types--custom-edges)
|
- [Edge Types & Custom Edges](#edge-types--custom-edges)
|
||||||
|
- [Edge Utils](#edge-utils)
|
||||||
- [Components](#components)
|
- [Components](#components)
|
||||||
- [Background](#background)
|
- [Background](#background)
|
||||||
- [Minimap](#minimap)
|
- [Minimap](#minimap)
|
||||||
@@ -282,6 +283,7 @@ If you wanted to display this edge, you would need a node with id = 1 (source no
|
|||||||
- `labelStyle`: css properties for the text
|
- `labelStyle`: css properties for the text
|
||||||
- `labelShowBg`: boolean - default: `true`
|
- `labelShowBg`: boolean - default: `true`
|
||||||
- `labelBgStyle`: css properties for the text background
|
- `labelBgStyle`: css properties for the text background
|
||||||
|
- `labelBgPadding`: [number, number] background rectangle padding - default: `[2, 4]`
|
||||||
- `arrowHeadType`: 'arrow' or 'arrowclosed' - defines the arrowhead of the edge
|
- `arrowHeadType`: 'arrow' or 'arrowclosed' - defines the arrowhead of the edge
|
||||||
- `markerEndId`: custom marker end url - if this is used `arrowHeadType` gets ignored
|
- `markerEndId`: custom marker end url - if this is used `arrowHeadType` gets ignored
|
||||||
- `isHidden`: if `true`, the edge will not be rendered
|
- `isHidden`: if `true`, the edge will not be rendered
|
||||||
@@ -289,7 +291,7 @@ If you wanted to display this edge, you would need a node with id = 1 (source no
|
|||||||
|
|
||||||
You can find an example with different edges in the [edges example](https://reactflow.dev/edges).
|
You can find an example with different edges in the [edges example](https://reactflow.dev/edges).
|
||||||
|
|
||||||
### Edge Types & Custom Edges
|
## Edge Types & Custom Edges
|
||||||
|
|
||||||
The basic edge types are `default` (bezier), `straight`, `step` and `smoothedge`. The default `edgeTypes` object looks like this:
|
The basic edge types are `default` (bezier), `straight`, `step` and `smoothedge`. The default `edgeTypes` object looks like this:
|
||||||
|
|
||||||
@@ -315,6 +317,49 @@ Now you could use the new type `special` for an edge.
|
|||||||
The `straight`, `default` and `step` types would still be available unless you overwrote one of them.
|
The `straight`, `default` and `step` types would still be available unless you overwrote one of them.
|
||||||
There is an implementation of a custom edge in the [edges example](/example/src/Edges/index.js).
|
There is an implementation of a custom edge in the [edges example](/example/src/Edges/index.js).
|
||||||
|
|
||||||
|
## Edge Utils
|
||||||
|
|
||||||
|
There are several utils that help you to create a custom edge. They are used in the [custom edge](/example/src/Edges/CustomEdge.js) example.
|
||||||
|
|
||||||
|
### getBezierPath
|
||||||
|
|
||||||
|
Returns the path of a bezier edge.
|
||||||
|
|
||||||
|
`getBezierPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
sourcePosition = Position.Bottom,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetPosition = Position.Top,
|
||||||
|
}: GetBezierPathParams): string`
|
||||||
|
|
||||||
|
### getSmoothStepPath
|
||||||
|
|
||||||
|
Returns the path of a smooth step edge. You can set `borderRadius` = `0` to get a step edge path.
|
||||||
|
|
||||||
|
`getSmoothStepPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
sourcePosition = Position.Bottom,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetPosition = Position.Top,
|
||||||
|
borderRadius = 5,
|
||||||
|
}: GetSmoothStepPathParams): string`
|
||||||
|
|
||||||
|
### getEdgeCenter
|
||||||
|
|
||||||
|
Returns the center poostion `[centerX, centerY]` of the edge.
|
||||||
|
|
||||||
|
`getEdgeCenter({ sourceX, sourceY, targetX, targetY }: GetCenterParams): [number, number, number, number]`
|
||||||
|
|
||||||
|
### getMarkerEnd
|
||||||
|
|
||||||
|
Returns the marker end url for displaying the arrow head.
|
||||||
|
|
||||||
|
`getMarkerEnd(arrowHeadType?: ArrowHeadType, markerEndId?: string): string`
|
||||||
|
|
||||||
# Components
|
# Components
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|||||||
@@ -1,14 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { getBezierPath, getMarkerEnd } from 'react-flow-renderer';
|
||||||
|
|
||||||
|
export default function CustomEdge({
|
||||||
|
id,
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
sourcePosition,
|
||||||
|
targetPosition,
|
||||||
|
style = {},
|
||||||
|
data,
|
||||||
|
arrowHeadType,
|
||||||
|
markerEndId,
|
||||||
|
}) {
|
||||||
|
const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition });
|
||||||
|
const markerEnd = getMarkerEnd(arrowHeadType, markerEndId);
|
||||||
|
|
||||||
export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY, style = {}, data }) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<path
|
<path id={id} style={style} className="react-flow__edge-path" d={edgePath} markerEnd={markerEnd} />
|
||||||
id={id}
|
|
||||||
style={style}
|
|
||||||
className="react-flow__edge-path"
|
|
||||||
d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`}
|
|
||||||
/>
|
|
||||||
<text>
|
<text>
|
||||||
<textPath href={`#${id}`} style={{ fontSize: '12px' }} startOffset="50%" textAnchor="middle">
|
<textPath href={`#${id}`} style={{ fontSize: '12px' }} startOffset="50%" textAnchor="middle">
|
||||||
{data.text}
|
{data.text}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const initialElements = [
|
|||||||
{ id: '6', type: 'output', data: { label: 'Output 6' }, position: { x: 50, y: 550 } },
|
{ id: '6', type: 'output', data: { label: 'Output 6' }, position: { x: 50, y: 550 } },
|
||||||
{ id: '7', type: 'output', data: { label: 'Output 7' }, position: { x: 250, y: 550 } },
|
{ id: '7', type: 'output', data: { label: 'Output 7' }, position: { x: 250, y: 550 } },
|
||||||
{ id: '8', type: 'output', data: { label: 'Output 8' }, position: { x: 525, y: 600 } },
|
{ id: '8', type: 'output', data: { label: 'Output 8' }, position: { x: 525, y: 600 } },
|
||||||
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)' },
|
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)', className: 'normal-edge' },
|
||||||
{ id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' },
|
{ id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' },
|
||||||
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
||||||
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
||||||
@@ -38,10 +38,11 @@ const initialElements = [
|
|||||||
source: '5',
|
source: '5',
|
||||||
target: '7',
|
target: '7',
|
||||||
label: 'label with styled bg',
|
label: 'label with styled bg',
|
||||||
labelBgStyle: { fill: '#eee', fillOpacity: 0.7 },
|
labelBgStyle: { fill: '#555', color: '#fff', fillOpacity: 0.7 },
|
||||||
arrowHeadType: 'arrowclosed',
|
arrowHeadType: 'arrowclosed',
|
||||||
|
labelBgPadding: [8, 4],
|
||||||
},
|
},
|
||||||
{ id: 'e5-8', source: '5', target: '8', type: 'custom', data: { text: 'custom edge' } },
|
{ id: 'e5-8', source: '5', target: '8', type: 'custom', data: { text: 'custom edge' }, arrowHeadType: 'arrowclosed' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const edgeTypes = {
|
const edgeTypes = {
|
||||||
|
|||||||
@@ -59,18 +59,12 @@ export default ({
|
|||||||
const targetY = (connectionPositionY - transform[1]) * (1 / transform[2]);
|
const targetY = (connectionPositionY - transform[1]) * (1 / transform[2]);
|
||||||
|
|
||||||
let dAttr: string = '';
|
let dAttr: string = '';
|
||||||
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;
|
|
||||||
const isRightOrLeft = sourceHandle?.position === Position.Left || sourceHandle?.position === Position.Right;
|
const isRightOrLeft = sourceHandle?.position === Position.Left || sourceHandle?.position === Position.Right;
|
||||||
const targetPosition = isRightOrLeft ? Position.Left : Position.Top;
|
const targetPosition = isRightOrLeft ? Position.Left : Position.Top;
|
||||||
|
|
||||||
if (connectionLineType === ConnectionLineType.Bezier) {
|
if (connectionLineType === ConnectionLineType.Bezier) {
|
||||||
dAttr = getBezierPath({
|
dAttr = getBezierPath({
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle?.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
@@ -80,10 +74,6 @@ export default ({
|
|||||||
});
|
});
|
||||||
} else if (connectionLineType === ConnectionLineType.Step) {
|
} else if (connectionLineType === ConnectionLineType.Step) {
|
||||||
dAttr = getSmoothStepPath({
|
dAttr = getSmoothStepPath({
|
||||||
xOffset,
|
|
||||||
yOffset,
|
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle?.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
@@ -94,10 +84,6 @@ export default ({
|
|||||||
});
|
});
|
||||||
} else if (connectionLineType === ConnectionLineType.SmoothStep) {
|
} else if (connectionLineType === ConnectionLineType.SmoothStep) {
|
||||||
dAttr = getSmoothStepPath({
|
dAttr = getSmoothStepPath({
|
||||||
xOffset,
|
|
||||||
yOffset,
|
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition: sourceHandle?.position,
|
sourcePosition: sourceHandle?.position,
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
|
|
||||||
import EdgeText from './EdgeText';
|
import EdgeText from './EdgeText';
|
||||||
import { getMarkerEnd } from './utils';
|
|
||||||
|
import { getMarkerEnd, getCenter } from './utils';
|
||||||
import { EdgeBezierProps, Position } from '../../types';
|
import { EdgeBezierProps, Position } from '../../types';
|
||||||
|
|
||||||
interface GetBezierPathParams {
|
interface GetBezierPathParams {
|
||||||
centerX: number;
|
|
||||||
centerY: number;
|
|
||||||
sourceX: number;
|
sourceX: number;
|
||||||
sourceY: number;
|
sourceY: number;
|
||||||
sourcePosition?: Position;
|
sourcePosition?: Position;
|
||||||
@@ -16,8 +15,6 @@ interface GetBezierPathParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getBezierPath({
|
export function getBezierPath({
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition = Position.Bottom,
|
sourcePosition = Position.Bottom,
|
||||||
@@ -25,10 +22,11 @@ export function getBezierPath({
|
|||||||
targetY,
|
targetY,
|
||||||
targetPosition = Position.Top,
|
targetPosition = Position.Top,
|
||||||
}: GetBezierPathParams): string {
|
}: GetBezierPathParams): string {
|
||||||
let path = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
|
const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||||
|
|
||||||
const leftAndRight = [Position.Left, Position.Right];
|
const leftAndRight = [Position.Left, Position.Right];
|
||||||
|
|
||||||
|
let path = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
|
||||||
|
|
||||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||||
path = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
|
path = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
|
||||||
} else if (leftAndRight.includes(targetPosition)) {
|
} else if (leftAndRight.includes(targetPosition)) {
|
||||||
@@ -55,16 +53,10 @@ export default memo(
|
|||||||
style,
|
style,
|
||||||
arrowHeadType,
|
arrowHeadType,
|
||||||
markerEndId,
|
markerEndId,
|
||||||
|
labelBgPadding,
|
||||||
}: EdgeBezierProps) => {
|
}: EdgeBezierProps) => {
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
|
||||||
|
|
||||||
const xOffset = Math.abs(targetX - sourceX) / 2;
|
|
||||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
|
||||||
|
|
||||||
const path = getBezierPath({
|
const path = getBezierPath({
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition,
|
sourcePosition,
|
||||||
@@ -81,6 +73,7 @@ export default memo(
|
|||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
labelShowBg={labelShowBg}
|
labelShowBg={labelShowBg}
|
||||||
labelBgStyle={labelBgStyle}
|
labelBgStyle={labelBgStyle}
|
||||||
|
labelBgPadding={labelBgPadding}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
|
|||||||
@@ -2,43 +2,44 @@ import React, { memo, useRef, useState, useEffect } from 'react';
|
|||||||
|
|
||||||
import { EdgeTextProps, Rect } from '../../types';
|
import { EdgeTextProps, Rect } from '../../types';
|
||||||
|
|
||||||
const textBgPadding = 2;
|
export default memo(
|
||||||
|
({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {}, labelBgPadding = [2, 4] }: EdgeTextProps) => {
|
||||||
|
const edgeRef = useRef<SVGTextElement>(null);
|
||||||
|
const [edgeTextBbox, setEdgeTextBbox] = useState<Rect>({ x: 0, y: 0, width: 0, height: 0 });
|
||||||
|
|
||||||
export default memo(({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {} }: EdgeTextProps) => {
|
useEffect(() => {
|
||||||
const edgeRef = useRef<SVGTextElement>(null);
|
if (edgeRef.current) {
|
||||||
const [edgeTextBbox, setEdgeTextBbox] = useState<Rect>({ x: 0, y: 0, width: 0, height: 0 });
|
const textBbox = edgeRef.current.getBBox();
|
||||||
|
|
||||||
useEffect(() => {
|
setEdgeTextBbox({
|
||||||
if (edgeRef.current) {
|
x: textBbox.x,
|
||||||
const textBbox = edgeRef.current.getBBox();
|
y: textBbox.y,
|
||||||
setEdgeTextBbox({
|
width: textBbox.width,
|
||||||
x: textBbox.x,
|
height: textBbox.height,
|
||||||
y: textBbox.y,
|
});
|
||||||
width: textBbox.width,
|
}
|
||||||
height: textBbox.height,
|
}, []);
|
||||||
});
|
|
||||||
|
if (typeof label === 'undefined' || !label) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (typeof label === 'undefined' || !label) {
|
return (
|
||||||
return null;
|
<g transform={`translate(${x - edgeTextBbox.width / 2} ${y - edgeTextBbox.height / 2})`}>
|
||||||
|
{labelShowBg && (
|
||||||
|
<rect
|
||||||
|
width={edgeTextBbox.width + 2 * labelBgPadding[0]}
|
||||||
|
x={-labelBgPadding[0]}
|
||||||
|
y={-labelBgPadding[1]}
|
||||||
|
height={edgeTextBbox.height + 2 * labelBgPadding[1]}
|
||||||
|
className="react-flow__edge-textbg"
|
||||||
|
style={labelBgStyle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<text className="react-flow__edge-text" y={edgeTextBbox.height / 2} dy="0.3em" ref={edgeRef} style={labelStyle}>
|
||||||
|
{label}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
return (
|
|
||||||
<g transform={`translate(${x - edgeTextBbox.width / 2} ${y - edgeTextBbox.height / 2})`}>
|
|
||||||
{labelShowBg && (
|
|
||||||
<rect
|
|
||||||
width={edgeTextBbox.width + 2 * textBgPadding}
|
|
||||||
x={-textBgPadding}
|
|
||||||
y={-textBgPadding}
|
|
||||||
height={edgeTextBbox.height + 2 * textBgPadding}
|
|
||||||
className="react-flow__edge-textbg"
|
|
||||||
style={labelBgStyle}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<text className="react-flow__edge-text" y={edgeTextBbox.height / 2} dy="0.3em" ref={edgeRef} style={labelStyle}>
|
|
||||||
{label}
|
|
||||||
</text>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
|
|
||||||
import EdgeText from './EdgeText';
|
import EdgeText from './EdgeText';
|
||||||
import { getMarkerEnd } from './utils';
|
import { getMarkerEnd, getCenter } from './utils';
|
||||||
import { EdgeSmoothStepProps, Position } from '../../types';
|
import { EdgeSmoothStepProps, Position } from '../../types';
|
||||||
|
|
||||||
// These are some helper methods for drawing the round corners
|
// These are some helper methods for drawing the round corners
|
||||||
@@ -34,10 +34,6 @@ const rightTopCorner = (cornerX: number, cornerY: number, cornerSize: number): s
|
|||||||
`L ${cornerX - cornerSize},${cornerY}Q ${cornerX},${cornerY} ${cornerX},${cornerY + cornerSize}`;
|
`L ${cornerX - cornerSize},${cornerY}Q ${cornerX},${cornerY} ${cornerX},${cornerY + cornerSize}`;
|
||||||
|
|
||||||
interface GetSmoothStepPathParams {
|
interface GetSmoothStepPathParams {
|
||||||
xOffset: number;
|
|
||||||
yOffset: number;
|
|
||||||
centerX: number;
|
|
||||||
centerY: number;
|
|
||||||
sourceX: number;
|
sourceX: number;
|
||||||
sourceY: number;
|
sourceY: number;
|
||||||
sourcePosition?: Position;
|
sourcePosition?: Position;
|
||||||
@@ -48,10 +44,6 @@ interface GetSmoothStepPathParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getSmoothStepPath({
|
export function getSmoothStepPath({
|
||||||
xOffset,
|
|
||||||
yOffset,
|
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition = Position.Bottom,
|
sourcePosition = Position.Bottom,
|
||||||
@@ -60,9 +52,10 @@ export function getSmoothStepPath({
|
|||||||
targetPosition = Position.Top,
|
targetPosition = Position.Top,
|
||||||
borderRadius = 5,
|
borderRadius = 5,
|
||||||
}: GetSmoothStepPathParams): string {
|
}: GetSmoothStepPathParams): string {
|
||||||
|
const [centerX, centerY, offsetX, offsetY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||||
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX));
|
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX));
|
||||||
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY));
|
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY));
|
||||||
const cornerSize = Math.min(cornerWidth, cornerHeight, xOffset, yOffset);
|
const cornerSize = Math.min(cornerWidth, cornerHeight, offsetX, offsetY);
|
||||||
|
|
||||||
const leftAndRight = [Position.Left, Position.Right];
|
const leftAndRight = [Position.Left, Position.Right];
|
||||||
|
|
||||||
@@ -138,6 +131,7 @@ export default memo(
|
|||||||
labelStyle,
|
labelStyle,
|
||||||
labelShowBg,
|
labelShowBg,
|
||||||
labelBgStyle,
|
labelBgStyle,
|
||||||
|
labelBgPadding,
|
||||||
style,
|
style,
|
||||||
sourcePosition = Position.Bottom,
|
sourcePosition = Position.Bottom,
|
||||||
targetPosition = Position.Top,
|
targetPosition = Position.Top,
|
||||||
@@ -145,17 +139,9 @@ export default memo(
|
|||||||
markerEndId,
|
markerEndId,
|
||||||
borderRadius = 5,
|
borderRadius = 5,
|
||||||
}: EdgeSmoothStepProps) => {
|
}: EdgeSmoothStepProps) => {
|
||||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
|
||||||
|
|
||||||
const xOffset = Math.abs(targetX - sourceX) / 2;
|
|
||||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
|
||||||
|
|
||||||
const path = getSmoothStepPath({
|
const path = getSmoothStepPath({
|
||||||
xOffset,
|
|
||||||
yOffset,
|
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition,
|
sourcePosition,
|
||||||
@@ -175,6 +161,7 @@ export default memo(
|
|||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
labelShowBg={labelShowBg}
|
labelShowBg={labelShowBg}
|
||||||
labelBgStyle={labelBgStyle}
|
labelBgStyle={labelBgStyle}
|
||||||
|
labelBgPadding={labelBgPadding}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export default memo(
|
|||||||
labelStyle,
|
labelStyle,
|
||||||
labelShowBg,
|
labelShowBg,
|
||||||
labelBgStyle,
|
labelBgStyle,
|
||||||
|
labelBgPadding,
|
||||||
style,
|
style,
|
||||||
arrowHeadType,
|
arrowHeadType,
|
||||||
markerEndId,
|
markerEndId,
|
||||||
@@ -33,6 +34,7 @@ export default memo(
|
|||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
labelShowBg={labelShowBg}
|
labelShowBg={labelShowBg}
|
||||||
labelBgStyle={labelBgStyle}
|
labelBgStyle={labelBgStyle}
|
||||||
|
labelBgPadding={labelBgPadding}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,25 @@ export const getMarkerEnd = (arrowHeadType?: ArrowHeadType, markerEndId?: string
|
|||||||
|
|
||||||
return typeof arrowHeadType !== 'undefined' ? `url(#react-flow__${arrowHeadType})` : 'none';
|
return typeof arrowHeadType !== 'undefined' ? `url(#react-flow__${arrowHeadType})` : 'none';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface GetCenterParams {
|
||||||
|
sourceX: number;
|
||||||
|
sourceY: number;
|
||||||
|
targetX: number;
|
||||||
|
targetY: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCenter = ({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
}: GetCenterParams): [number, number, number, number] => {
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ interface EdgeWrapperProps {
|
|||||||
label?: string;
|
label?: string;
|
||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle: CSSProperties;
|
labelBgStyle?: CSSProperties;
|
||||||
|
labelBgPadding?: [number, number];
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick?: (event: React.MouseEvent, edge: Edge) => void;
|
onClick?: (event: React.MouseEvent, edge: Edge) => void;
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
@@ -36,6 +37,7 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
|||||||
labelStyle,
|
labelStyle,
|
||||||
labelShowBg,
|
labelShowBg,
|
||||||
labelBgStyle,
|
labelBgStyle,
|
||||||
|
labelBgPadding,
|
||||||
className,
|
className,
|
||||||
isHidden,
|
isHidden,
|
||||||
data,
|
data,
|
||||||
@@ -77,6 +79,7 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
|||||||
labelStyle={labelStyle}
|
labelStyle={labelStyle}
|
||||||
labelShowBg={labelShowBg}
|
labelShowBg={labelShowBg}
|
||||||
labelBgStyle={labelBgStyle}
|
labelBgStyle={labelBgStyle}
|
||||||
|
labelBgPadding={labelBgPadding}
|
||||||
data={data}
|
data={data}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ function renderEdge(
|
|||||||
<EdgeComponent
|
<EdgeComponent
|
||||||
key={edge.id}
|
key={edge.id}
|
||||||
id={edge.id}
|
id={edge.id}
|
||||||
|
className={edge.className}
|
||||||
type={edge.type}
|
type={edge.type}
|
||||||
data={edge.data}
|
data={edge.data}
|
||||||
onClick={props.onElementClick}
|
onClick={props.onElementClick}
|
||||||
@@ -170,6 +171,7 @@ function renderEdge(
|
|||||||
labelStyle={edge.labelStyle}
|
labelStyle={edge.labelStyle}
|
||||||
labelShowBg={edge.labelShowBg}
|
labelShowBg={edge.labelShowBg}
|
||||||
labelBgStyle={edge.labelBgStyle}
|
labelBgStyle={edge.labelBgStyle}
|
||||||
|
labelBgPadding={edge.labelBgPadding}
|
||||||
style={edge.style}
|
style={edge.style}
|
||||||
arrowHeadType={edge.arrowHeadType}
|
arrowHeadType={edge.arrowHeadType}
|
||||||
source={sourceId}
|
source={sourceId}
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ const useElementUpdater = (propElements: Elements): void => {
|
|||||||
edgeProps.labelShowBg = propEdge.labelShowBg;
|
edgeProps.labelShowBg = propEdge.labelShowBg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof propEdge.labelBgPadding !== 'undefined') {
|
||||||
|
edgeProps.labelBgPadding = propEdge.labelBgPadding;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof labelBgStyle !== 'undefined') {
|
if (typeof labelBgStyle !== 'undefined') {
|
||||||
edgeProps.labelBgStyle = labelBgStyle;
|
edgeProps.labelBgStyle = labelBgStyle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ export default ReactFlow;
|
|||||||
|
|
||||||
export { default as Handle } from './components/Handle';
|
export { default as Handle } from './components/Handle';
|
||||||
export { default as EdgeText } from './components/Edges/EdgeText';
|
export { default as EdgeText } from './components/Edges/EdgeText';
|
||||||
|
export { getBezierPath } from './components/Edges/BezierEdge';
|
||||||
|
export { getSmoothStepPath } from './components/Edges/SmoothStepEdge';
|
||||||
|
export { getMarkerEnd, getCenter as getEdgeCenter } from './components/Edges/utils';
|
||||||
|
|
||||||
export { isNode, isEdge, removeElements, addEdge, getOutgoers } from './utils/graph';
|
export { isNode, isEdge, removeElements, addEdge, getOutgoers } from './utils/graph';
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export interface Edge {
|
|||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle?: CSSProperties;
|
labelBgStyle?: CSSProperties;
|
||||||
|
labelBgPadding?: [number, number];
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
arrowHeadType?: ArrowHeadType;
|
arrowHeadType?: ArrowHeadType;
|
||||||
@@ -96,6 +97,7 @@ export interface EdgeProps {
|
|||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle?: CSSProperties;
|
labelBgStyle?: CSSProperties;
|
||||||
|
labelBgPadding?: [number, number];
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
arrowHeadType?: ArrowHeadType;
|
arrowHeadType?: ArrowHeadType;
|
||||||
markerEndId?: string;
|
markerEndId?: string;
|
||||||
@@ -235,6 +237,7 @@ export interface EdgeCompProps {
|
|||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle?: CSSProperties;
|
labelBgStyle?: CSSProperties;
|
||||||
|
labelBgPadding?: [number, number];
|
||||||
onClick?: (event: ReactMouseEvent, edge: Edge) => void;
|
onClick?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
@@ -248,6 +251,7 @@ export interface EdgeTextProps {
|
|||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle?: CSSProperties;
|
labelBgStyle?: CSSProperties;
|
||||||
|
labelBgPadding?: [number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NodePosUpdate = {
|
export type NodePosUpdate = {
|
||||||
|
|||||||
Reference in New Issue
Block a user