Im trying to create flowchart using reactflow drag and drop in react js. Below is my basic code I have written
This is my Test.js
import React, { useState, useRef, useCallback } from 'react';
import ReactFlow, {
ReactFlowProvider,
addEdge,
useNodesState,
useEdgesState,
Controls,
MarkerType,
useReactFlow,
getIncomers,
getOutgoers,
} from 'reactflow';
import Sidebar from './Utils/Sidebar';
import Conditional from './Shapes/Conditional'
import Input from './Shapes/Input'
import Output from './Shapes/Output'
import Start from './Shapes/Start'
import Stop from './Shapes/Stop'
import Process from './Shapes/Process'
import 'reactflow/dist/style.css';
import './visual.scss'
const initialNodes = [
{
id: '1',
type: 'start',
data: { label: 'start' },
position: { x: 0, y: 0 },
},
];
const fitViewOptions = { minZoom: 0 }
const nodeTypes = { conditional: Conditional, inpt: Input, outpt: Output, start: Start, stop: Stop, rectangle: Process }
let id = 0;
const getId = () => `node_${id++}`;
const Test1 = () => {
const reactFlowWrapper = useRef(null);
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [reactFlowInstance, setReactFlowInstance] = useState(null);
const reactFlow = useReactFlow()
// reactFlow.getNodes().map(it => {
// console.log(it)
// })
// console.log(getOutgoers(nodes,edges))
const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), []);
const onDragOver = useCallback((event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
}, []);
const onDrop = useCallback(
(event) => {
event.preventDefault();
// console.log(reactFlow.getNodes())
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect();
// console.log(countNodes());
const type = event.dataTransfer.getData('application/reactflow');
// check if the dropped element is valid
if (typeof type === 'undefined' || !type) {
return;
}
// console.log(reactFlowWrapper.current.offsetWidth - event.clientX - reactFlowBounds.left)
// console.log(event.clientY)
const position = reactFlowInstance.project({
x: event.clientX - reactFlowBounds.left - 100,
y: event.clientY - reactFlowBounds.top - 40,
});
const newNode = {
id: getId(),
type,
position,
data: { label: `${type}` },
}
// if(type === 'conditional'){
// newNode = {}
// }else{
// newNode = {
// id: getId(),
// type,
// position,
// data: { label: `${type}` },
// };
// }
// const newEdge = {
// id: getId(),
// source
// }
setNodes((nds) => nds.concat(newNode));
},
[reactFlowInstance]
);
return (
<div className="reactflow-wrapper" ref={reactFlowWrapper}>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onInit={setReactFlowInstance}
onDrop={onDrop}
onDragOver={onDragOver}
nodeTypes={nodeTypes}
fitView
fitViewOptions={fitViewOptions}
>
{/* <Controls /> */}
</ReactFlow>
</div>
);
};
const Test = () => {
return (
<div className="dndflow">
<ReactFlowProvider>
<Test1 />
<Sidebar />
</ReactFlowProvider>
</div>
)
}
export default Test
This is my Sidebar.js
import ITEMS from "./Svgshapes";
const Sidebar = () => {
// console.log("items", ITEMS)
const onDragStart = (event, nodeType) => {
event.dataTransfer.setData('application/reactflow', nodeType);
event.dataTransfer.effectAllowed = 'move';
};
return (
<aside>
{/* <div className="description">You can drag these nodes to the pane on the right.</div> */}
<div className="nodeitems-todrag">
{ITEMS.map(item => (
<div onDragStart={(event) => onDragStart(event, item.type)} draggable>
{item.content}
</div>
))}
</div>
{/* <div className="dndnode" onDragStart={(event) => onDragStart(event, 'default')} draggable>
Default Node
</div>
<div className="dndnode output" onDragStart={(event) => onDragStart(event, 'output')} draggable>
Output Node
</div> */}
</aside>
);
}
export default Sidebar
This is my items.js where I have created svg shapes
const decisionsvg = () => {
return (
<svg viewBox="0 0 70 50">
<rect x={20} y={12} width="30" height="30" style={{ fill: 'none', strokeWidth: 3, stroke: 'rgb(1,1,1)', transformOrigin: 'center', transform: 'rotate(45deg)' }} />
</svg>
)
}
const startsvg = () => {
return (
<svg viewBox="0 0 70 50">
<rect rx={15} ry='50%' x={5} y={10} width="50" height="25" style={{ fill: 'none', strokeWidth: 3, stroke: 'rgb(1,1,1)' }} />
</svg>
)
}
const stopsvg = () => {
return (
<svg viewBox="0 0 70 50">
<rect rx={15} ry='50%' x={5} y={10} width="50" height="25" style={{ fill: 'none', strokeWidth: 3, stroke: 'rgb(1,1,1)' }} />
</svg>
)
}
const inputsvg = () => {
return (
<svg viewBox="0 0 70 50">
<rect x={25} y={10} width="40" height="25" style={{ fill: 'none', strokeWidth: 3, stroke: 'rgb(1,1,1)' }} transform="skewX(-20)" />
</svg>
)
}
const outputsvg = () => {
return (
<svg viewBox="0 0 70 50">
<rect x={25} y={10} width="40" height="25" style={{ fill: 'none', strokeWidth: 3, stroke: 'rgb(1,1,1)' }} transform="skewX(-20)" />
</svg>
)
}
const processsvg = () => {
return (
<svg viewBox="0 0 70 50">
<rect x={5} y={10} width="50" height="25" style={{ fill: 'none', strokeWidth: 3, stroke: 'rgb(1,1,1)' }} />
</svg>
)
}
const ITEMS = [
{
id: 1,
type: 'start',
content: startsvg(),
},
{
id: 2,
type: 'stop',
content: stopsvg(),
},
{
id: 3,
type: 'conditional',
content: decisionsvg()
},
{
id: 4,
type: 'rectangle',
content: processsvg()
},
{
id: 5,
type: 'inpt',
content: inputsvg(),
},
{
id: 6,
type: 'outpt',
content: outputsvg(),
},
]
export default ITEMS
I have also created custom nodes
Start.js
import { useCallback } from 'react';
import { Handle, Position } from 'reactflow';
const Start = ({ data }) => {
// console.log(data);
return (
<div className="startnode">
{/* <Handle type="target" position={Position.Top} /> */}
<div>
<label htmlFor="text">{data.label}</label>
{/* <input id="text" name="text" onChange={onChange} /> */}
</div>
{/* <Handle type="source" position={Position.Bottom} id="a" style={handleStyle} /> */}
<Handle type="source" position={Position.Bottom} id="b" />
</div>
);
}
export default Start
Stop.js
import { useCallback } from 'react';
import { Handle, Position } from 'reactflow';
const Stop = ({ data }) => {
// console.log(data);
return (
<div className="stopnode">
<Handle type="target" position={Position.Top} />
<div>
<label htmlFor="text">{data.label}</label>
{/* <input id="text" name="text" onChange={onChange} /> */}
</div>
{/* <Handle type="source" position={Position.Bottom} id="a" style={handleStyle} /> */}
{/* <Handle type="source" position={Position.Bottom} id="b" /> */}
</div>
);
}
export default Stop
This basic code is all I have from the reactflow docs. Please help