How to create a flowchart using drag and drop using reactflow in react js

414 views Asked by At

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

0

There are 0 answers