Merge pull request #207 from wbkd/feat-edgetext

feat(edges): add label and labelBg options
This commit is contained in:
Moritz
2020-05-11 12:22:54 +02:00
committed by GitHub
24 changed files with 406 additions and 74 deletions
+9 -3
View File
@@ -31,7 +31,7 @@ React Flow is a library for building node-based graphs. You can easily implement
* **Plugin system:** [Mini map and graph controls](#plugins)
* **Reliable**: Written in [Typescript](https://www.typescriptlang.org/) and tested with [cypress](https://www.cypress.io/)
In order to make this library as flexible as possible we dont do any state updates besides the positions. This means that you need to pass all functions that change the displayed nodes and edges by yourself. You can implement your own ones or use the helper functions that come with the library.
In order to make this library as flexible as possible we dont do any state updates besides the positions. This means that you need to pass all functions that change the displayed nodes and edges by yourself. You can implement your own ones or use the helper functions that come with the library.
## Installation
@@ -130,7 +130,7 @@ You can find an example of how to implement a custom node in the [custom node ex
There are three [edge types](#edge-types--custom-edges) (`straight`, `default`, `step`) you can use. The default type is `default`. You can also create [custom edges](#edge-types--custom-edges).
Edge example: `{ id: 'e1-2', type: 'straight', source: '1', target: '2', animated: true }`
Edge example: `{ id: 'e1-2', type: 'straight', source: '1', target: '2', animated: true, label: 'edge label' }`
### Props
@@ -139,7 +139,13 @@ Edge example: `{ id: 'e1-2', type: 'straight', source: '1', target: '2', animate
- `target`: string (an id of a node) *(required)*
- `type`: 'input' | 'output' | 'default' or a custom one you implemented
- `animated`: boolean
- `style`: css properties
- `style`: css properties for the edge line path
- `label`: string
- `labelStyle`: css properties for the text
- `labelShowBg`: boolean - default: `true`
- `labelBgStyle`: css properties for the text background
You can find an example with lots of different edges in the [edges example](https://react-flow.netlify.app/edges).
### Edge Types / Custom Edges
+51 -12
View File
@@ -6896,7 +6896,7 @@ function renderEdge(edge, props, nodes, selectedElements, isInteractive) {
var targetPosition = targetHandle ? targetHandle.position : Position.Top;
var _c = getEdgePositions(sourceNode, sourceHandle, sourcePosition, targetNode, targetHandle, targetPosition), sourceX = _c.sourceX, sourceY = _c.sourceY, targetX = _c.targetX, targetY = _c.targetY;
var isSelected = selectedElements.some(function (elm) { return isEdge(elm) && elm.source === sourceId && elm.target === targetId; });
return (React__default.createElement(EdgeComponent, { key: edge.id, id: edge.id, type: edge.type, onClick: props.onElementClick, selected: isSelected, animated: edge.animated, style: edge.style, source: sourceId, target: targetId, sourceHandleId: sourceHandleId, targetHandleId: targetHandleId, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, isInteractive: isInteractive }));
return (React__default.createElement(EdgeComponent, { key: edge.id, id: edge.id, type: edge.type, 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, sourceHandleId: sourceHandleId, targetHandleId: targetHandleId, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, isInteractive: isInteractive }));
}
var EdgeRenderer = memo(function (props) {
var _a = useStoreState$1(function (s) { return ({
@@ -9270,38 +9270,77 @@ function createNodeTypes(nodeTypes) {
return __assign(__assign({}, standardTypes), specialTypes);
}
var textBgPadding = 2;
var EdgeText = memo(function (_a) {
var x = _a.x, y = _a.y, label = _a.label, _b = _a.labelStyle, labelStyle = _b === void 0 ? {} : _b, _c = _a.labelShowBg, labelShowBg = _c === void 0 ? true : _c, _d = _a.labelBgStyle, labelBgStyle = _d === void 0 ? {} : _d;
var edgeRef = useRef(null);
var _e = useState({ x: 0, y: 0, width: 0, height: 0 }), edgeTextBbox = _e[0], setEdgeTextBbox = _e[1];
useEffect(function () {
if (edgeRef.current) {
var 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 (React__default.createElement("g", { transform: "translate(" + (x - edgeTextBbox.width / 2) + " " + (y - edgeTextBbox.height / 2) + ")" },
labelShowBg && (React__default.createElement("rect", { width: edgeTextBbox.width + 2 * textBgPadding, x: -textBgPadding, y: -textBgPadding, height: edgeTextBbox.height + 2 * textBgPadding, className: "react-flow__edge-textbg", style: labelBgStyle })),
React__default.createElement("text", { className: "react-flow__edge-text", y: edgeTextBbox.height / 2, dy: "0.3em", ref: edgeRef, style: labelStyle }, label)));
});
var BezierEdge = memo(function (_a) {
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.sourcePosition, sourcePosition = _b === void 0 ? Position.Bottom : _b, _c = _a.targetPosition, targetPosition = _c === void 0 ? Position.Top : _c, _d = _a.style, style = _d === void 0 ? {} : _d;
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.sourcePosition, sourcePosition = _b === void 0 ? Position.Bottom : _b, _c = _a.targetPosition, targetPosition = _c === void 0 ? Position.Top : _c, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, _d = _a.style, style = _d === void 0 ? {} : _d;
var yOffset = Math.abs(targetY - sourceY) / 2;
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
var xOffset = Math.abs(targetX - sourceX) / 2;
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
var dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + centerY + " " + targetX + "," + centerY + " " + targetX + "," + targetY;
var leftAndRight = [Position.Left, Position.Right];
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
var xOffset = Math.abs(targetX - sourceX) / 2;
var 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 React__default.createElement("path", __assign({}, style, { d: dAttr }));
var text = label ? (React__default.createElement(EdgeText, { x: centerX, y: centerY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle })) : null;
return (React__default.createElement("g", null,
React__default.createElement("path", { style: style, d: dAttr, className: "react-flow__edge-path" }),
text));
});
var StraightEdge = memo(function (_a) {
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.style, style = _b === void 0 ? {} : _b;
return (React__default.createElement("path", __assign({}, style, { d: "M " + sourceX + "," + sourceY + "L " + targetX + "," + targetY })));
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, _b = _a.style, style = _b === void 0 ? {} : _b;
var yOffset = Math.abs(targetY - sourceY) / 2;
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
var xOffset = Math.abs(targetX - sourceX) / 2;
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
var text = label ? (React__default.createElement(EdgeText, { x: centerX, y: centerY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle })) : null;
return (React__default.createElement("g", null,
React__default.createElement("path", { style: style, className: "react-flow__edge-path", d: "M " + sourceX + "," + sourceY + "L " + targetX + "," + targetY }),
text));
});
var StepEdge = memo(function (_a) {
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.style, style = _b === void 0 ? {} : _b;
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, _b = _a.style, style = _b === void 0 ? {} : _b;
var yOffset = Math.abs(targetY - sourceY) / 2;
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
return (React__default.createElement("path", __assign({}, style, { d: "M " + sourceX + "," + sourceY + "L " + sourceX + "," + centerY + "L " + targetX + "," + centerY + "L " + targetX + "," + targetY })));
var xOffset = Math.abs(targetX - sourceX) / 2;
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
var text = label ? (React__default.createElement(EdgeText, { x: centerX, y: centerY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle })) : null;
return (React__default.createElement("g", null,
React__default.createElement("path", { style: style, className: "react-flow__edge-path", d: "M " + sourceX + "," + sourceY + "L " + sourceX + "," + centerY + "L " + targetX + "," + centerY + "L " + targetX + "," + targetY }),
text));
});
var wrapEdge = (function (EdgeComponent) {
var EdgeWrapper = memo(function (_a) {
var id = _a.id, source = _a.source, target = _a.target, type = _a.type, animated = _a.animated, selected = _a.selected, onClick = _a.onClick, isInteractive = _a.isInteractive, rest = __rest(_a, ["id", "source", "target", "type", "animated", "selected", "onClick", "isInteractive"]);
var id = _a.id, source = _a.source, target = _a.target, type = _a.type, animated = _a.animated, selected = _a.selected, onClick = _a.onClick, isInteractive = _a.isInteractive, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, rest = __rest(_a, ["id", "source", "target", "type", "animated", "selected", "onClick", "isInteractive", "label", "labelStyle", "labelShowBg", "labelBgStyle"]);
var edgeClasses = classnames('react-flow__edge', { selected: selected, animated: animated });
var onEdgeClick = function () {
if (!isInteractive) {
@@ -9311,7 +9350,7 @@ var wrapEdge = (function (EdgeComponent) {
onClick({ id: id, source: source, target: target, type: type });
};
return (React__default.createElement("g", { className: edgeClasses, onClick: onEdgeClick },
React__default.createElement(EdgeComponent, __assign({ id: id, source: source, target: target, type: type, animated: animated, selected: selected, onClick: onClick }, rest))));
React__default.createElement(EdgeComponent, __assign({ id: id, source: source, target: target, type: type, animated: animated, selected: selected, onClick: onClick, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle }, rest))));
});
EdgeWrapper.displayName = 'EdgeWrapper';
return EdgeWrapper;
@@ -9359,7 +9398,7 @@ function styleInject(css, ref) {
}
}
var css_248z = ".react-flow {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.react-flow__renderer {\n width: 100%;\n height: 100%;\n position: absolute;\n}\n\n.react-flow__zoompane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1;\n}\n\n.react-flow__selectionpane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.react-flow__selection {\n position: absolute;\n top: 0;\n left: 0;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n}\n\n.react-flow__edges {\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n z-index: 2;\n}\n\n.react-flow__edge {\n fill: none;\n stroke: #bbb;\n stroke-width: 2;\n pointer-events: all;\n}\n\n.react-flow__edge.selected {\n stroke: #555;\n }\n\n.react-flow__edge.animated {\n stroke-dasharray: 5;\n -webkit-animation: dashdraw 0.5s linear infinite;\n animation: dashdraw 0.5s linear infinite;\n }\n\n.react-flow__edge.connection {\n stroke: '#ddd';\n pointer-events: none;\n }\n\n@-webkit-keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n.react-flow__nodes {\n width: 100%;\n height: 100%;\n position: absolute;\n z-index: 3;\n pointer-events: none;\n transform-origin: 0 0;\n}\n\n.is-interactive .react-flow__node {\n cursor: -webkit-grab;\n cursor: grab;\n }\n\n.is-interactive .react-flow__node:hover > * {\n box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);\n }\n\n.is-interactive .react-flow__handle {\n cursor: crosshair;\n }\n\n.react-flow__node {\n position: absolute;\n color: #222;\n font-family: sans-serif;\n font-size: 12px;\n text-align: center;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n}\n\n.react-flow__node.selected > * {\n box-shadow: 0 0 0 2px #555;\n }\n\n.react-flow__handle {\n position: absolute;\n width: 10px;\n height: 8px;\n background: rgba(255, 255, 255, 0.4);\n}\n\n.react-flow__handle.bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.top {\n left: 50%;\n top: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n }\n\n.react-flow__handle.right {\n right: 0;\n top: 50%;\n transform: translate(0, -50%);\n }\n\n.react-flow__nodesselection {\n z-index: 3;\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n transform-origin: left top;\n pointer-events: none;\n}\n\n.react-flow__nodesselection-rect {\n position: absolute;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n pointer-events: all;\n }\n\n.react-flow__controls {\n box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);\n}\n\n.react-flow__controls-button {\n background: #fefefe;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 16px;\n height: 16px;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n padding: 5px;\n }\n\n.react-flow__controls-button svg {\n width: 100%;\n }\n\n.react-flow__controls-button:hover {\n background: #f4f4f4;\n }\n";
var css_248z = ".react-flow {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.react-flow__renderer {\n width: 100%;\n height: 100%;\n position: absolute;\n}\n\n.react-flow__zoompane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1;\n}\n\n.react-flow__selectionpane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.react-flow__selection {\n position: absolute;\n top: 0;\n left: 0;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n}\n\n.react-flow__edges {\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n z-index: 2;\n}\n\n.react-flow__edge {\n pointer-events: all;\n}\n\n.react-flow__edge.animated path {\n stroke-dasharray: 5;\n -webkit-animation: dashdraw 0.5s linear infinite;\n animation: dashdraw 0.5s linear infinite;\n }\n\n.react-flow__edge.connection {\n stroke: '#ddd';\n pointer-events: none;\n }\n\n.react-flow__edge-path {\n fill: none;\n stroke: #bbb;\n stroke-width: 2;\n}\n\n.react-flow__edge-path.selected {\n stroke: #555;\n }\n\n.react-flow__edge-text {\n font-size: 12px;\n pointer-events: none;\n}\n\n.react-flow__edge-textbg {\n fill: white;\n}\n\n@-webkit-keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n.react-flow__nodes {\n width: 100%;\n height: 100%;\n position: absolute;\n z-index: 3;\n pointer-events: none;\n transform-origin: 0 0;\n}\n\n.is-interactive .react-flow__node {\n cursor: -webkit-grab;\n cursor: grab;\n }\n\n.is-interactive .react-flow__node:hover > * {\n box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);\n }\n\n.is-interactive .react-flow__handle {\n cursor: crosshair;\n }\n\n.react-flow__node {\n position: absolute;\n color: #222;\n font-family: sans-serif;\n font-size: 12px;\n text-align: center;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n}\n\n.react-flow__node.selected > * {\n box-shadow: 0 0 0 2px #555;\n }\n\n.react-flow__handle {\n position: absolute;\n width: 10px;\n height: 8px;\n background: rgba(255, 255, 255, 0.4);\n}\n\n.react-flow__handle.bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.top {\n left: 50%;\n top: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n }\n\n.react-flow__handle.right {\n right: 0;\n top: 50%;\n transform: translate(0, -50%);\n }\n\n.react-flow__nodesselection {\n z-index: 3;\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n transform-origin: left top;\n pointer-events: none;\n}\n\n.react-flow__nodesselection-rect {\n position: absolute;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n pointer-events: all;\n }\n\n.react-flow__controls {\n box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);\n}\n\n.react-flow__controls-button {\n background: #fefefe;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 16px;\n height: 16px;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n padding: 5px;\n }\n\n.react-flow__controls-button svg {\n width: 100%;\n }\n\n.react-flow__controls-button:hover {\n background: #f4f4f4;\n }\n";
styleInject(css_248z);
var ReactFlow = function (_a) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+51 -12
View File
@@ -6903,7 +6903,7 @@ function renderEdge(edge, props, nodes, selectedElements, isInteractive) {
var targetPosition = targetHandle ? targetHandle.position : Position.Top;
var _c = getEdgePositions(sourceNode, sourceHandle, sourcePosition, targetNode, targetHandle, targetPosition), sourceX = _c.sourceX, sourceY = _c.sourceY, targetX = _c.targetX, targetY = _c.targetY;
var isSelected = selectedElements.some(function (elm) { return isEdge(elm) && elm.source === sourceId && elm.target === targetId; });
return (React__default.createElement(EdgeComponent, { key: edge.id, id: edge.id, type: edge.type, onClick: props.onElementClick, selected: isSelected, animated: edge.animated, style: edge.style, source: sourceId, target: targetId, sourceHandleId: sourceHandleId, targetHandleId: targetHandleId, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, isInteractive: isInteractive }));
return (React__default.createElement(EdgeComponent, { key: edge.id, id: edge.id, type: edge.type, 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, sourceHandleId: sourceHandleId, targetHandleId: targetHandleId, sourceX: sourceX, sourceY: sourceY, targetX: targetX, targetY: targetY, sourcePosition: sourcePosition, targetPosition: targetPosition, isInteractive: isInteractive }));
}
var EdgeRenderer = React.memo(function (props) {
var _a = useStoreState$1(function (s) { return ({
@@ -9277,38 +9277,77 @@ function createNodeTypes(nodeTypes) {
return __assign(__assign({}, standardTypes), specialTypes);
}
var textBgPadding = 2;
var EdgeText = React.memo(function (_a) {
var x = _a.x, y = _a.y, label = _a.label, _b = _a.labelStyle, labelStyle = _b === void 0 ? {} : _b, _c = _a.labelShowBg, labelShowBg = _c === void 0 ? true : _c, _d = _a.labelBgStyle, labelBgStyle = _d === void 0 ? {} : _d;
var edgeRef = React.useRef(null);
var _e = React.useState({ x: 0, y: 0, width: 0, height: 0 }), edgeTextBbox = _e[0], setEdgeTextBbox = _e[1];
React.useEffect(function () {
if (edgeRef.current) {
var 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 (React__default.createElement("g", { transform: "translate(" + (x - edgeTextBbox.width / 2) + " " + (y - edgeTextBbox.height / 2) + ")" },
labelShowBg && (React__default.createElement("rect", { width: edgeTextBbox.width + 2 * textBgPadding, x: -textBgPadding, y: -textBgPadding, height: edgeTextBbox.height + 2 * textBgPadding, className: "react-flow__edge-textbg", style: labelBgStyle })),
React__default.createElement("text", { className: "react-flow__edge-text", y: edgeTextBbox.height / 2, dy: "0.3em", ref: edgeRef, style: labelStyle }, label)));
});
var BezierEdge = React.memo(function (_a) {
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.sourcePosition, sourcePosition = _b === void 0 ? Position.Bottom : _b, _c = _a.targetPosition, targetPosition = _c === void 0 ? Position.Top : _c, _d = _a.style, style = _d === void 0 ? {} : _d;
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.sourcePosition, sourcePosition = _b === void 0 ? Position.Bottom : _b, _c = _a.targetPosition, targetPosition = _c === void 0 ? Position.Top : _c, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, _d = _a.style, style = _d === void 0 ? {} : _d;
var yOffset = Math.abs(targetY - sourceY) / 2;
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
var xOffset = Math.abs(targetX - sourceX) / 2;
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
var dAttr = "M" + sourceX + "," + sourceY + " C" + sourceX + "," + centerY + " " + targetX + "," + centerY + " " + targetX + "," + targetY;
var leftAndRight = [Position.Left, Position.Right];
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
var xOffset = Math.abs(targetX - sourceX) / 2;
var 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 React__default.createElement("path", __assign({}, style, { d: dAttr }));
var text = label ? (React__default.createElement(EdgeText, { x: centerX, y: centerY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle })) : null;
return (React__default.createElement("g", null,
React__default.createElement("path", { style: style, d: dAttr, className: "react-flow__edge-path" }),
text));
});
var StraightEdge = React.memo(function (_a) {
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.style, style = _b === void 0 ? {} : _b;
return (React__default.createElement("path", __assign({}, style, { d: "M " + sourceX + "," + sourceY + "L " + targetX + "," + targetY })));
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, _b = _a.style, style = _b === void 0 ? {} : _b;
var yOffset = Math.abs(targetY - sourceY) / 2;
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
var xOffset = Math.abs(targetX - sourceX) / 2;
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
var text = label ? (React__default.createElement(EdgeText, { x: centerX, y: centerY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle })) : null;
return (React__default.createElement("g", null,
React__default.createElement("path", { style: style, className: "react-flow__edge-path", d: "M " + sourceX + "," + sourceY + "L " + targetX + "," + targetY }),
text));
});
var StepEdge = React.memo(function (_a) {
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, _b = _a.style, style = _b === void 0 ? {} : _b;
var sourceX = _a.sourceX, sourceY = _a.sourceY, targetX = _a.targetX, targetY = _a.targetY, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, _b = _a.style, style = _b === void 0 ? {} : _b;
var yOffset = Math.abs(targetY - sourceY) / 2;
var centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
return (React__default.createElement("path", __assign({}, style, { d: "M " + sourceX + "," + sourceY + "L " + sourceX + "," + centerY + "L " + targetX + "," + centerY + "L " + targetX + "," + targetY })));
var xOffset = Math.abs(targetX - sourceX) / 2;
var centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
var text = label ? (React__default.createElement(EdgeText, { x: centerX, y: centerY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle })) : null;
return (React__default.createElement("g", null,
React__default.createElement("path", { style: style, className: "react-flow__edge-path", d: "M " + sourceX + "," + sourceY + "L " + sourceX + "," + centerY + "L " + targetX + "," + centerY + "L " + targetX + "," + targetY }),
text));
});
var wrapEdge = (function (EdgeComponent) {
var EdgeWrapper = React.memo(function (_a) {
var id = _a.id, source = _a.source, target = _a.target, type = _a.type, animated = _a.animated, selected = _a.selected, onClick = _a.onClick, isInteractive = _a.isInteractive, rest = __rest(_a, ["id", "source", "target", "type", "animated", "selected", "onClick", "isInteractive"]);
var id = _a.id, source = _a.source, target = _a.target, type = _a.type, animated = _a.animated, selected = _a.selected, onClick = _a.onClick, isInteractive = _a.isInteractive, label = _a.label, labelStyle = _a.labelStyle, labelShowBg = _a.labelShowBg, labelBgStyle = _a.labelBgStyle, rest = __rest(_a, ["id", "source", "target", "type", "animated", "selected", "onClick", "isInteractive", "label", "labelStyle", "labelShowBg", "labelBgStyle"]);
var edgeClasses = classnames('react-flow__edge', { selected: selected, animated: animated });
var onEdgeClick = function () {
if (!isInteractive) {
@@ -9318,7 +9357,7 @@ var wrapEdge = (function (EdgeComponent) {
onClick({ id: id, source: source, target: target, type: type });
};
return (React__default.createElement("g", { className: edgeClasses, onClick: onEdgeClick },
React__default.createElement(EdgeComponent, __assign({ id: id, source: source, target: target, type: type, animated: animated, selected: selected, onClick: onClick }, rest))));
React__default.createElement(EdgeComponent, __assign({ id: id, source: source, target: target, type: type, animated: animated, selected: selected, onClick: onClick, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle }, rest))));
});
EdgeWrapper.displayName = 'EdgeWrapper';
return EdgeWrapper;
@@ -9366,7 +9405,7 @@ function styleInject(css, ref) {
}
}
var css_248z = ".react-flow {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.react-flow__renderer {\n width: 100%;\n height: 100%;\n position: absolute;\n}\n\n.react-flow__zoompane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1;\n}\n\n.react-flow__selectionpane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.react-flow__selection {\n position: absolute;\n top: 0;\n left: 0;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n}\n\n.react-flow__edges {\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n z-index: 2;\n}\n\n.react-flow__edge {\n fill: none;\n stroke: #bbb;\n stroke-width: 2;\n pointer-events: all;\n}\n\n.react-flow__edge.selected {\n stroke: #555;\n }\n\n.react-flow__edge.animated {\n stroke-dasharray: 5;\n -webkit-animation: dashdraw 0.5s linear infinite;\n animation: dashdraw 0.5s linear infinite;\n }\n\n.react-flow__edge.connection {\n stroke: '#ddd';\n pointer-events: none;\n }\n\n@-webkit-keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n.react-flow__nodes {\n width: 100%;\n height: 100%;\n position: absolute;\n z-index: 3;\n pointer-events: none;\n transform-origin: 0 0;\n}\n\n.is-interactive .react-flow__node {\n cursor: -webkit-grab;\n cursor: grab;\n }\n\n.is-interactive .react-flow__node:hover > * {\n box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);\n }\n\n.is-interactive .react-flow__handle {\n cursor: crosshair;\n }\n\n.react-flow__node {\n position: absolute;\n color: #222;\n font-family: sans-serif;\n font-size: 12px;\n text-align: center;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n}\n\n.react-flow__node.selected > * {\n box-shadow: 0 0 0 2px #555;\n }\n\n.react-flow__handle {\n position: absolute;\n width: 10px;\n height: 8px;\n background: rgba(255, 255, 255, 0.4);\n}\n\n.react-flow__handle.bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.top {\n left: 50%;\n top: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n }\n\n.react-flow__handle.right {\n right: 0;\n top: 50%;\n transform: translate(0, -50%);\n }\n\n.react-flow__nodesselection {\n z-index: 3;\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n transform-origin: left top;\n pointer-events: none;\n}\n\n.react-flow__nodesselection-rect {\n position: absolute;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n pointer-events: all;\n }\n\n.react-flow__controls {\n box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);\n}\n\n.react-flow__controls-button {\n background: #fefefe;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 16px;\n height: 16px;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n padding: 5px;\n }\n\n.react-flow__controls-button svg {\n width: 100%;\n }\n\n.react-flow__controls-button:hover {\n background: #f4f4f4;\n }\n";
var css_248z = ".react-flow {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.react-flow__renderer {\n width: 100%;\n height: 100%;\n position: absolute;\n}\n\n.react-flow__zoompane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1;\n}\n\n.react-flow__selectionpane {\n width: 100%;\n height: 100%;\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n}\n\n.react-flow__selection {\n position: absolute;\n top: 0;\n left: 0;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n}\n\n.react-flow__edges {\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n z-index: 2;\n}\n\n.react-flow__edge {\n pointer-events: all;\n}\n\n.react-flow__edge.animated path {\n stroke-dasharray: 5;\n -webkit-animation: dashdraw 0.5s linear infinite;\n animation: dashdraw 0.5s linear infinite;\n }\n\n.react-flow__edge.connection {\n stroke: '#ddd';\n pointer-events: none;\n }\n\n.react-flow__edge-path {\n fill: none;\n stroke: #bbb;\n stroke-width: 2;\n}\n\n.react-flow__edge-path.selected {\n stroke: #555;\n }\n\n.react-flow__edge-text {\n font-size: 12px;\n pointer-events: none;\n}\n\n.react-flow__edge-textbg {\n fill: white;\n}\n\n@-webkit-keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n@keyframes dashdraw {\n from {\n stroke-dashoffset: 10;\n }\n}\n\n.react-flow__nodes {\n width: 100%;\n height: 100%;\n position: absolute;\n z-index: 3;\n pointer-events: none;\n transform-origin: 0 0;\n}\n\n.is-interactive .react-flow__node {\n cursor: -webkit-grab;\n cursor: grab;\n }\n\n.is-interactive .react-flow__node:hover > * {\n box-shadow: 0 1px 5px 2px rgba(0, 0, 0, 0.08);\n }\n\n.is-interactive .react-flow__handle {\n cursor: crosshair;\n }\n\n.react-flow__node {\n position: absolute;\n color: #222;\n font-family: sans-serif;\n font-size: 12px;\n text-align: center;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n pointer-events: all;\n transform-origin: 0 0;\n}\n\n.react-flow__node.selected > * {\n box-shadow: 0 0 0 2px #555;\n }\n\n.react-flow__handle {\n position: absolute;\n width: 10px;\n height: 8px;\n background: rgba(255, 255, 255, 0.4);\n}\n\n.react-flow__handle.bottom {\n top: auto;\n left: 50%;\n bottom: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.top {\n left: 50%;\n top: 0;\n transform: translate(-50%, 0);\n }\n\n.react-flow__handle.left {\n top: 50%;\n left: 0;\n transform: translate(0, -50%);\n }\n\n.react-flow__handle.right {\n right: 0;\n top: 50%;\n transform: translate(0, -50%);\n }\n\n.react-flow__nodesselection {\n z-index: 3;\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n transform-origin: left top;\n pointer-events: none;\n}\n\n.react-flow__nodesselection-rect {\n position: absolute;\n background: rgba(0, 89, 220, 0.08);\n border: 1px dotted rgba(0, 89, 220, 0.8);\n pointer-events: all;\n }\n\n.react-flow__controls {\n box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08);\n}\n\n.react-flow__controls-button {\n background: #fefefe;\n border-bottom: 1px solid #eee;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 16px;\n height: 16px;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n padding: 5px;\n }\n\n.react-flow__controls-button svg {\n width: 100%;\n }\n\n.react-flow__controls-button:hover {\n background: #f4f4f4;\n }\n";
styleInject(css_248z);
var ReactFlow = function (_a) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,4 +1,4 @@
import React from 'react';
import { EdgeBezierProps } from '../../types';
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, }: EdgeBezierProps) => JSX.Element>;
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, label, labelStyle, labelShowBg, labelBgStyle, style, }: EdgeBezierProps) => JSX.Element>;
export default _default;
+4
View File
@@ -0,0 +1,4 @@
import React from 'react';
import { EdgeTextProps } from '../../types';
declare const _default: React.MemoExoticComponent<({ x, y, label, labelStyle, labelShowBg, labelBgStyle }: EdgeTextProps) => JSX.Element | null>;
export default _default;
+1 -1
View File
@@ -1,4 +1,4 @@
import React from 'react';
import { EdgeProps } from '../../types';
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: EdgeProps) => JSX.Element>;
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: EdgeProps) => JSX.Element>;
export default _default;
+1 -1
View File
@@ -1,4 +1,4 @@
import React from 'react';
import { EdgeProps } from '../../types';
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: EdgeProps) => JSX.Element>;
declare const _default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: EdgeProps) => JSX.Element>;
export default _default;
+6 -2
View File
@@ -1,14 +1,18 @@
import React from 'react';
import React, { CSSProperties } from 'react';
import { ElementId, Edge, EdgeCompProps } from '../../types';
interface EdgeWrapperProps {
id: ElementId;
source: ElementId;
target: ElementId;
type: any;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle: CSSProperties;
onClick: (edge: Edge) => void;
animated: boolean;
selected: boolean;
isInteractive: boolean;
}
declare const _default: (EdgeComponent: React.ComponentType<EdgeCompProps>) => React.MemoExoticComponent<({ id, source, target, type, animated, selected, onClick, isInteractive, ...rest }: EdgeWrapperProps) => JSX.Element>;
declare const _default: (EdgeComponent: React.ComponentType<EdgeCompProps>) => React.MemoExoticComponent<({ id, source, target, type, animated, selected, onClick, isInteractive, label, labelStyle, labelShowBg, labelBgStyle, ...rest }: EdgeWrapperProps) => JSX.Element>;
export default _default;
+3 -3
View File
@@ -40,9 +40,9 @@ declare const ReactFlow: {
output: ({ data, style, targetPosition }: import("../../types").NodeProps) => JSX.Element;
};
edgeTypes: {
default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style, }: import("../../types").EdgeBezierProps) => JSX.Element>;
straight: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: import("../../types").EdgeProps) => JSX.Element>;
step: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, style }: import("../../types").EdgeProps) => JSX.Element>;
default: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, label, labelStyle, labelShowBg, labelBgStyle, style, }: import("../../types").EdgeBezierProps) => JSX.Element>;
straight: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: import("../../types").EdgeProps) => JSX.Element>;
step: React.MemoExoticComponent<({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, style }: import("../../types").EdgeProps) => JSX.Element>;
};
connectionLineType: string;
connectionLineStyle: {};
+23 -3
View File
@@ -1,4 +1,4 @@
import { CSSProperties, SVGAttributes } from 'react';
import { CSSProperties } from 'react';
export declare type ElementId = string;
export declare type Elements = Array<Node | Edge>;
export declare type Transform = [number, number, number];
@@ -51,7 +51,11 @@ export interface Edge {
type?: string;
source: ElementId;
target: ElementId;
style?: SVGAttributes<{}>;
label?: string;
labelStyle?: CSSProperties;
labelShowBg?: boolean;
labelBgStyle?: CSSProperties;
style?: CSSProperties;
animated?: boolean;
}
export interface EdgeProps {
@@ -59,7 +63,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 {
sourcePosition: Position;
@@ -127,8 +135,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;
}
export {};
+1 -1
View File
@@ -11,7 +11,7 @@ const initialElements = [
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-2', source: '1', target: '2', animated: true, label: 'edge text' },
{ id: 'e1-3', source: '1', target: '3' },
];
+51
View File
@@ -0,0 +1,51 @@
import React, { useState } from 'react';
import ReactFlow, { removeElements, addEdge, MiniMap, Controls } from 'react-flow-renderer';
const onNodeDragStop = node => console.log('drag stop', node);
const onElementClick = element => console.log('click', element);
const onLoad = (graph) => {
graph.fitView();
};
const initialElements = [
{ id: '1', type: 'input', data: { label: 'Input Node 1' }, position: { x: 250, y: 0 } },
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
{ id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
{ id: '5', data: { label: 'Node 5' }, position: { x: 450, y: 400 } },
{ id: '6', type: 'output', data: { label: 'Output Node 5' }, position: { x: 250, y: 550 } },
{ id: '7', type: 'output', data: { label: 'Output Node 6' }, position: { x: 550, y: 550 } },
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge', labelBgStyle: { fillOpacity: 0.75 } },
{ 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-5', source: '4', target: '5', animated: true, label: 'animated styled edge', style: { stroke: 'red' } },
{ id: 'e5-6', source: '5', target: '6', label: 'styled label', labelStyle: { fill: 'red', fontWeight: 700 } },
{ id: 'e5-7', source: '5', target: '7', label: 'label with styled bg', labelBgStyle: { fill: '#eee', fillOpacity: 0.7 } },
]
const EdgesFlow = () => {
const [elements, setElements] = useState(initialElements);
const onElementsRemove = (elementsToRemove) => setElements(els => removeElements(elementsToRemove, els));
const onConnect = (params) => setElements(els => addEdge(params, els));
return (
<ReactFlow
elements={elements}
onElementClick={onElementClick}
onElementsRemove={onElementsRemove}
onConnect={onConnect}
onNodeDragStop={onNodeDragStop}
style={{ width: '100%', height: '100%' }}
onLoad={onLoad}
snapToGrid={true}
>
<MiniMap />
<Controls />
</ReactFlow>
);
}
export default EdgesFlow;
+3 -3
View File
@@ -18,13 +18,13 @@ const initialElements = [
sourcePosition: 'right'
},
{ id: '4', data: { label: 'Node 4' }, position: { x: 500, y: 200 }, targetPosition: 'left' },
{ id: '5', type: 'output', data: { label: 'Output Node 5'}, position: { x: 300, y: 300 } },
{ id: '5', type: 'output', data: { label: 'Output Node 5' }, position: { x: 300, y: 300 } },
{ id: '6', type: 'output', data: { label: 'Output Node 6' }, position: { x: 600, y: 400 } },
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-2', source: '1', target: '2', animated: true, label: 'edge text', labelBgStyle: { fillOpacity: 0.75 } },
{ id: 'e2-3', source: '2', target: '3', animated: true },
{ id: 'e3-4', source: '3', target: '4', animated: true },
{ id: 'e3-5', source: '4', target: '5', animated: true, type: 'step' },
{ id: 'e5-6b', source: '4', target: '6', type: 'step' },
{ id: 'e5-6b', source: '4', target: '6', type: 'step', label: 'styled label', labelStyle: { fill: 'red', fontWeight: 700 } },
]
const RichGraph = () => {
+6 -1
View File
@@ -8,6 +8,7 @@ import CustomNode from './CustomNode';
import Stress from './Stress';
import Inactive from './Inactive';
import Empty from './Empty';
import Edges from './Edges';
import './index.css';
@@ -27,10 +28,14 @@ const routes = [{
path: '/stress',
component: Stress,
label: 'Stress'
}, {
path: '/edges',
component: Edges,
label: 'Edges'
}, {
path: '/empty',
component: Empty
},{
}, {
path: '/inactive',
component: Inactive
}];
+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;
}