如何在react js中使用reactflow通过拖放创建流程图

问题描述 投票:0回答:1

我尝试在 React JS 中使用 ReactFlow 拖放来创建流程图。 下面是我写的基本代码

这是我的 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

这是我的 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

这是我的 items.js,我在其中创建了 svg 形状

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

我还创建了自定义节点

开始.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

这个基本代码是我从reactflow文档中得到的全部内容。请帮忙

reactjs flowchart react-flow
1个回答
0
投票

按照此完成reactflow中的拖放 https://reactflow.dev/examples/interaction/drag-and-drop

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.