feat(edges): add label props

This commit is contained in:
moklick
2020-05-11 12:18:36 +02:00
parent 6a35e576a0
commit 0c30eebb94
24 changed files with 406 additions and 74 deletions
+25 -4
View File
@@ -1,5 +1,6 @@
import React, { memo } from 'react';
import EdgeText from './EdgeText';
import { EdgeBezierProps, Position } from '../../types';
export default memo(
@@ -10,23 +11,43 @@ export default memo(
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
style = {},
}: EdgeBezierProps) => {
const yOffset = Math.abs(targetY - sourceY) / 2;
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
let dAttr = `M${sourceX},${sourceY} C${sourceX},${centerY} ${targetX},${centerY} ${targetX},${targetY}`;
const leftAndRight = [Position.Left, Position.Right];
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
dAttr = `M${sourceX},${sourceY} C${centerX},${sourceY} ${centerX},${targetY} ${targetX},${targetY}`;
} else if (leftAndRight.includes(sourcePosition) || leftAndRight.includes(targetPosition)) {
dAttr = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
}
return <path {...style} d={dAttr} />;
const text = label ? (
<EdgeText
x={centerX}
y={centerY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
/>
) : null;
return (
<g>
<path style={style} d={dAttr} className="react-flow__edge-path" />
{text}
</g>
);
}
);
+44
View File
@@ -0,0 +1,44 @@
import React, { memo, useRef, useState, useEffect } from 'react';
import { EdgeTextProps, Rect } from '../../types';
const textBgPadding = 2;
export default memo(({ x, y, label, labelStyle = {}, labelShowBg = true, labelBgStyle = {} }: EdgeTextProps) => {
const edgeRef = useRef<SVGTextElement>(null);
const [edgeTextBbox, setEdgeTextBbox] = useState<Rect>({ x: 0, y: 0, width: 0, height: 0 });
useEffect(() => {
if (edgeRef.current) {
const textBbox = edgeRef.current.getBBox();
setEdgeTextBbox({
x: textBbox.x,
y: textBbox.y,
width: textBbox.width,
height: textBbox.height,
});
}
}, []);
if (typeof label === 'undefined' || !label) {
return null;
}
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>
);
});
+24 -5
View File
@@ -1,17 +1,36 @@
import React, { memo } from 'react';
import EdgeText from './EdgeText';
import { EdgeProps } from '../../types';
export default memo(
({ sourceX, sourceY, targetX, targetY, style = {} }: EdgeProps) => {
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style = {} }: EdgeProps) => {
const yOffset = Math.abs(targetY - sourceY) / 2;
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
return (
<path
{...style}
d={`M ${sourceX},${sourceY}L ${sourceX},${centerY}L ${targetX},${centerY}L ${targetX},${targetY}`}
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
const text = label ? (
<EdgeText
x={centerX}
y={centerY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
/>
) : null;
return (
<g>
<path
style={style}
className="react-flow__edge-path"
d={`M ${sourceX},${sourceY}L ${sourceX},${centerY}L ${targetX},${centerY}L ${targetX},${targetY}`}
/>
{text}
</g>
);
}
);
+23 -2
View File
@@ -1,11 +1,32 @@
import React, { memo } from 'react';
import EdgeText from './EdgeText';
import { EdgeProps } from '../../types';
export default memo(
({ sourceX, sourceY, targetX, targetY, style = {} }: EdgeProps) => {
({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style = {} }: EdgeProps) => {
const yOffset = Math.abs(targetY - sourceY) / 2;
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
const text = label ? (
<EdgeText
x={centerX}
y={centerY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
/>
) : null;
return (
<path {...style} d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`} />
<g>
<path style={style} className="react-flow__edge-path" d={`M ${sourceX},${sourceY}L ${targetX},${targetY}`} />
{text}
</g>
);
}
);
+24 -2
View File
@@ -1,4 +1,4 @@
import React, { memo, ComponentType } from 'react';
import React, { memo, ComponentType, CSSProperties } from 'react';
import cx from 'classnames';
import store from '../../store';
@@ -9,6 +9,10 @@ interface EdgeWrapperProps {
source: ElementId;
target: ElementId;
type: any;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle: CSSProperties;
onClick: (edge: Edge) => void;
animated: boolean;
selected: boolean;
@@ -17,7 +21,21 @@ interface EdgeWrapperProps {
export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
const EdgeWrapper = memo(
({ id, source, target, type, animated, selected, onClick, isInteractive, ...rest }: EdgeWrapperProps) => {
({
id,
source,
target,
type,
animated,
selected,
onClick,
isInteractive,
label,
labelStyle,
labelShowBg,
labelBgStyle,
...rest
}: EdgeWrapperProps) => {
const edgeClasses = cx('react-flow__edge', { selected, animated });
const onEdgeClick = (): void => {
if (!isInteractive) {
@@ -38,6 +56,10 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
animated={animated}
selected={selected}
onClick={onClick}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
{...rest}
/>
</g>
+9 -5
View File
@@ -83,7 +83,7 @@ function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleE
if (bounds.length === 1 || !handleId) {
handle = bounds[0];
} else if (handleId) {
handle = bounds.find(d => d.id === handleId);
handle = bounds.find((d) => d.id === handleId);
}
return handle;
@@ -123,8 +123,8 @@ function renderEdge(
const [sourceId, sourceHandleId] = edge.source.split('__');
const [targetId, targetHandleId] = edge.target.split('__');
const sourceNode = nodes.find(n => n.id === sourceId);
const targetNode = nodes.find(n => n.id === targetId);
const sourceNode = nodes.find((n) => n.id === sourceId);
const targetNode = nodes.find((n) => n.id === targetId);
if (!sourceNode) {
throw new Error(`couldn't create edge for source id: ${sourceId}`);
@@ -155,7 +155,7 @@ function renderEdge(
);
const isSelected = (selectedElements as Edge[]).some(
elm => isEdge(elm) && elm.source === sourceId && elm.target === targetId
(elm) => isEdge(elm) && elm.source === sourceId && elm.target === targetId
);
return (
@@ -166,6 +166,10 @@ function renderEdge(
onClick={props.onElementClick}
selected={isSelected}
animated={edge.animated}
label={edge.label}
labelStyle={edge.labelStyle}
labelShowBg={edge.labelShowBg}
labelBgStyle={edge.labelBgStyle}
style={edge.style}
source={sourceId}
target={targetId}
@@ -191,7 +195,7 @@ const EdgeRenderer = memo((props: EdgeRendererProps) => {
connectionPosition: { x, y },
selectedElements,
isInteractive,
} = useStoreState(s => ({
} = useStoreState((s) => ({
transform: s.transform,
edges: s.edges,
nodes: s.nodes,
+20 -8
View File
@@ -46,16 +46,9 @@
}
.react-flow__edge {
fill: none;
stroke: #bbb;
stroke-width: 2;
pointer-events: all;
&.selected {
stroke: #555;
}
&.animated {
&.animated path {
stroke-dasharray: 5;
animation: dashdraw 0.5s linear infinite;
}
@@ -66,6 +59,25 @@
}
}
.react-flow__edge-path {
fill: none;
stroke: #bbb;
stroke-width: 2;
&.selected {
stroke: #555;
}
}
.react-flow__edge-text {
font-size: 12px;
pointer-events: none;
}
.react-flow__edge-textbg {
fill: white;
}
@keyframes dashdraw {
from {
stroke-dashoffset: 10;
+24 -3
View File
@@ -1,4 +1,4 @@
import { CSSProperties, SVGAttributes } from 'react';
import { CSSProperties } from 'react';
export type ElementId = string;
@@ -63,7 +63,11 @@ export interface Edge {
type?: string;
source: ElementId;
target: ElementId;
style?: SVGAttributes<{}>;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle?: CSSProperties;
style?: CSSProperties;
animated?: boolean;
}
@@ -72,7 +76,11 @@ export interface EdgeProps {
sourceY: number;
targetX: number;
targetY: number;
style?: SVGAttributes<{}>;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle?: CSSProperties;
style?: CSSProperties;
}
export interface EdgeBezierProps extends EdgeProps {
@@ -151,7 +159,20 @@ export interface EdgeCompProps {
source: ElementId;
target: ElementId;
type: any;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle?: CSSProperties;
onClick?: (edge: Edge) => void;
animated?: boolean;
selected?: boolean;
}
export interface EdgeTextProps {
x: number;
y: number;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle?: CSSProperties;
}