首页 > 解决方案 > 单击按钮时如何禁用 Edhehandles?

问题描述

我有用于添加节点和添加边的单独按钮。当我单击添加边缘按钮(名称:流)时,边缘手柄变为活动状态。使用 eh.enable() 函数。当我使用 eh.disable();eh.hide() 函数开始箭头绘制过程时,我在侧句柄选项中添加了 stop 函数,或者当箭头绘制完成时,它会关闭。

当我单击添加节点按钮时,我还想停止边缘句柄。我包含在 stopAddEdge() 函数中的 eh.disable();eh.hide() 函数没有提供此功能。按下按钮时如何禁用边缘手柄。我应该在哪里以及如何使用 eh.disable() 函数?

我的项目由两个组件组成,

MyParentComponent.jsx ;

import React, { useState, useEffect } from 'react';
import { DownCircleOutlined, SyncOutlined, MinusCircleOutlined, ArrowRightOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import 'antd/dist/antd.css';
import NewComponent from './NewComponent';


const MyParentComponent = () => {
    const [nodeType, setNodeType] = useState("");
    const [flowModeOn, setFlowModeOn] = useState(false);


    useEffect(() => {

    }, []);

    const handleEvent = (e) => {
        console.log(e.currentTarget);
        console.log(e.currentTarget.value);
        const btnValue = e.currentTarget.value;
        setNodeType(btnValue);
        setFlowModeOn(false); 
    };

    const stopAddNode = (params) => {
        setNodeType(params);
    }

    const flowModeEvent = () => {
        setFlowModeOn(true);
        setNodeType("");
    };

    const ChangeFlowMode = (params) => {
        setFlowModeOn(params);
    };
    return (
        <div>
            <div style={{ textAlign: "center" }}>
                <h1> My Cytoscape App </h1>
                <div>
                    <Button value="startNode" shape="round" icon={<DownCircleOutlined />} size='large' onClick={handleEvent}>Start</Button>
                    <Button value="activity" shape="round" icon={<SyncOutlined />} size='large' onClick={handleEvent}>Activity</Button>
                    <Button value="endNode" shape="round" icon={<MinusCircleOutlined />} size='large' onClick={handleEvent}>End</Button>

                    <Button value="edge" shape="round" icon={<ArrowRightOutlined />} size='large' onClick={() => flowModeEvent()}>Flow</Button>
                </div>

                <h3>Selected Items:  {nodeType}</h3>

            </div>

            <NewComponent nodeType={nodeType} stopAddNode={stopAddNode} flowModeOn={flowModeOn} ChangeFlowMode={ChangeFlowMode} />

        </div>
    );
};

export default MyParentComponent;

新组件.jsx;

import React, { useEffect, useState, useRef } from 'react';
import CytoscapeComponent from 'react-cytoscapejs';
import Cytoscape from 'cytoscape';
import edgehandles from 'cytoscape-edgehandles';
import contextMenus from 'cytoscape-context-menus';
import 'cytoscape-context-menus/cytoscape-context-menus.css';

Cytoscape.use(edgehandles);
Cytoscape.use(contextMenus);

const NewComponent = (props) => {

  const cyRef = useRef();
  const [controlStartState, setControlStartState] = useState(-1);
  const [controlEndState, setControlEndState] = useState(-1);

  const [nodeArray, setNodeArray] = useState([]);
  const [currentNodeArray, setCurrentNodeArray] = useState([]);
  const [ehStoped, setEhStoped] = useState(true)

  let eh;

  useEffect(() => {
    eh = cyRef.current.edgehandles(edgehandlesOptions);
    eh.disable();
  });


  useEffect(() => {
    cyRef.current.contextMenus(contextMenuOptions);
  }, []);

  
  useEffect(() => {
    console.log("props.flowModeOn: " + props.flowModeOn);
    console.log("ehStoped: " + ehStoped);


    if (props.flowModeOn === true && ehStoped ===true) {
      if (cyRef.current) {
        console.log("add edgein hemen üstü");
        addEdge(); 
      }
    }
    else if (props.flowModeOn === false) {
      if (cyRef.current) {
      console.log("stopAddEdgein hemen üstü");
      stopAddEdge();
      }
    }
  }, [props.flowModeOn]);

  const edgehandlesOptions = {
    preview: true, // whether to show added edges preview before releasing selection
    hoverDelay: 150, // time spent hovering over a target node before it is considered selected
    handleNodes: 'node', // selector/filter function for whether edges can be made from a given node
    snap: false, // when enabled, the edge can be drawn by just moving close to a target node
    snapThreshold: 50, // the target node must be less than or equal to this many pixels away from the cursor/finger
    snapFrequency: 15, // the number of times per second (Hz) that snap checks done (lower is less expensive)
    noEdgeEventsInDraw: false, // set events:no to edges during draws, prevents mouseouts on compounds
    disableBrowserGestures: true, // during an edge drawing gesture, disable browser gestures such as two-finger trackpad swipe and pinch-to-zoom
    handlePosition: function (node) {
      return 'middle top'; // sets the position of the handle in the format of "X-AXIS Y-AXIS" such as "left top", "middle top"
    },
    handleInDrawMode: false, // whether to show the handle in draw mode
    edgeType: function (sourceNode, targetNode) {
      // can return 'flat' for flat edges between nodes or 'node' for intermediate node between them
      // returning null/undefined means an edge can't be added between the two nodes
      return 'flat';
    },
    loopAllowed: function (node) {
      // for the specified node, return whether edges from itself to itself are allowed
      return false;
    },
    nodeLoopOffset: -50, // offset for edgeType: 'node' loops
    nodeParams: function (sourceNode, targetNode) {
      // for edges between the specified source and target
      // return element object to be passed to cy.add() for intermediary node
      return {};
    },
    edgeParams: function (sourceNode, targetNode, i) {
      // for edges between the specified source and target
      // return element object to be passed to cy.add() for edge
      // NB: i indicates edge index in case of edgeType: 'node'
      return {};
    },
    ghostEdgeParams: function () {
      // return element object to be passed to cy.add() for the ghost edge
      // (default classes are always added for you)
      return {};
    },
    show: function (sourceNode) {
      // fired when handle is shown
    },
    hide: function (sourceNode) {
      // fired when the handle is hidden
      console.log("options içindeki HİDE fonksiyonu");
    },
    start: function (sourceNode) {
      // fired when edgehandles interaction starts (drag on handle)
    },
    complete: function (sourceNode, targetNode, addedEles) {
      // fired when edgehandles is done and elements are added
      // console.log("addedEles: ");
      // console.log(addedEles);

      // cyRef.current.remove(addedEles);
    },
    stop: function (sourceNode) {
      // fired when edgehandles interaction is stopped (either complete with added edges or incomplete)

      eh.disable();
      eh.hide();
      console.log("options içindeki stop fonksiyonu");
      props.ChangeFlowMode(false);
      setEhStoped(true);
    console.log("ehStoped: " + ehStoped);

    },
    cancel: function (sourceNode, cancelledTargets) {
      // fired when edgehandles are cancelled (incomplete gesture)
      console.log("options içindeki cancel fonksiyonu");

    },
    hoverover: function (sourceNode, targetNode) {
      // fired when a target is hovered
    },
    hoverout: function (sourceNode, targetNode) {
      // fired when a target isn't hovered anymore
    },
    previewon: function (sourceNode, targetNode, previewEles) {
      console.log("previewon qqqqq");

      // fired when preview is shown
    },
    previewoff: function (sourceNode, targetNode, previewEles) {
      // fired when preview is hidden
      console.log("previewoff");
    },
    drawon: function () {
      // fired when draw mode enabled
      console.log("drawon");
    },
    drawoff: function () {
      // fired when draw mode disabled
      console.log("options içindeki drawoff fonksiyonu");
    }
  };

  const addEdge = () => {
    console.log("1 addEdge ehStoped: " + ehStoped);

      console.log("add adge enable");
      // @ts-ignore
      eh.enable();
      setEhStoped(false);
    console.log("2 addEdge ehStoped: " + ehStoped);

  }

  const stopAddEdge = () => {
      console.log("stop Add edge fonksiyonu");
        // eh.destroy();
        // eh.stop();
        // eh.disableDrawMode()
        eh.disable();
        eh.hide();
        // props.ChangeFlowMode(false);
  }

  const elements = [
    { data: { id: "one", label: "Comp1", type: 'comp' }, position: { x: 20, y: 200 } },
    // { data: { id: "two", label: "Node 2" }, position: { x: 120, y: 200 } },
    // { data: { id: "three", label: "Node 3" }, position: { x: 220, y: 200 } },
    // { data: { id: "four", label: "Node 4" }, position: { x: 320, y: 200 } },
    // { data: { source: "one", target: "two", label: "Edge from Node1 to Node2" } }
  ];

  const styleSheet = [
    {
      selector: 'node',
      style: {
        // 'background-color': '#000',
        'color': '#1e2829',
        'label': 'data(label)',
        //opacity: 0.3
        'width': '80',
        'height': '80',
        'text-wrap': 'wrap',
        'text-valign': 'center',
        'text-halign': 'center',
        'border-width': '1px',
        'border-color': 'black'
      }
    },

    {
      selector: 'node[type="comp"]',
      style: {
        'background-color': '#822',
      }
    },
    {
      selector: ".startNode",
      style: {
        backgroundColor: "green",

        'border-width': '1px',
        'border-color': 'black'
      }
    },
    {
      selector: ".rectangleNode",
      style: {
        'shape': 'rectangle',
        'width': 250,
        'height': 150,
        'content': 'data(label)',
        'text-wrap': 'wrap',
        'text-valign': 'center',
        'text-halign': 'center',
        'border-width': '1px',
        'border-color': 'black'
      }
    },
    {
      selector: ".endNode",
      style: {
        backgroundColor: "#aa0000",

        'border-width': '1px',
        'border-color': 'black'
      }
    },
    {
      selector: 'edge',
      style: {
        'width': 2,
        'line-color': '#ccc',
        'target-arrow-color': '#ccc',
        'target-arrow-shape': 'triangle',
        'curve-style': 'bezier',
      }
    },

    // some style for the Edge Handles !!!

    {
      selector: '.eh-handle',
      style: {
        // 'background-color': '#1abc9c',
        'background-color': 'red',
        'width': 12,
        'height': 12,
        'shape': 'barrel',
        'overlay-opacity': 0,
        'border-width': 12, // makes the handle easier to hit
        'border-opacity': 0
      }
    },

    {
      selector: '.eh-hover',
      css: {
        'background-color': 'red'
      }
    },

    {
      selector: '.eh-source', //ok tamamlanmadan önceki kaynak görüntüsü
      css: {
        'border-width': 2,
        'border-color': 'red'
      }
    },

    {
      selector: '.eh-target', //ok tamamlanmadan önceki hedef görüntüsü
      css: {
        'border-width': 2,
        'background-color': 'red',
        'border-color': 'red'
      }
    },

    {
      selector: '.eh-preview, .eh-ghost-edge',
      css: {
        'line-color': 'red',
        'target-arrow-color': 'red',
        'source-arrow-color': 'red'
      }
    },
    {
      selector: 'node:selected',
      style:
      {
        'background-color': '#ffc90e',
        'border-color': '#ffc90e', /*#f1c40f'*/
      }
    },
    {
      selector: 'edge:selected',
      style:
      {
        'width': 3,
        'line-color': '#ffc90e',
        'target-arrow-color': '#ffc90e'
      }
    },

  ];

  const contextMenuOptions = {
    evtType: 'cxttap',
    menuItems: [
      {
        id: 'add edge',
        content: 'add edge',
        tooltipText: 'add edge',
        selector: 'node',
        onClickFunction: function (event) {
          console.log("label: " + event.target.data().label);
          console.log("id: " + event.target.data().id);

          // eh.start(cyRef.current.$('node:selected'));
        },
        hasTrailingDivider: true
      },
      {
        id: 'edit',
        content: 'edit',
        tooltipText: 'edit with text area content',
        selector: 'node, edge',
        onClickFunction: function (event) {
          console.log("ID: " + event.target.data().label);
        },
        hasTrailingDivider: true
      },
      {
        id: 'remove',
        content: 'remove',
        tooltipText: 'remove',
        // image: { src: "assets/remove.svg", width: 12, height: 12, x: 6, y: 4 },
        selector: 'node, edge',
        onClickFunction: function (event) {

          console.log("ID: " + event.target.data().id);
          var target = event.target || event.cyTarget;
          var removed = target.remove();
          console.log(removed);

        },
        hasTrailingDivider: true
      }
    ],
    submenuIndicator: { src: 'assets/submenu-indicator-default.svg', width: 12, height: 12 }
  };

  var tempCurrentNodeArray = [];
  var controlStart, controlEnd = null;

  const mousedownEvent = () => {

    cyRef.current.nodes().unlock();

    var typeIds = cyRef.current.elements('node');

    for (var i = 0; i < typeIds.length; i++) {
      tempCurrentNodeArray.push(typeIds[i].data().label);
    }

    setCurrentNodeArray(tempCurrentNodeArray);


    controlStart = tempCurrentNodeArray.indexOf("startNode");

    setControlStartState(controlStart);

    controlEnd = tempCurrentNodeArray.indexOf("endNode");

    setControlEndState(controlEnd);
  }

  const addNode = (evt) => {
    
    var evtTarget = evt.target;
    if (evtTarget === cyRef.current) {

      if (props.nodeType == "startNode") {
        if (controlStartState == -1) {

          // console.log('tap on background');
          cyRef.current.add({
            group: 'nodes',
            data: {
              weight: 175,
              label: props.nodeType,
            },
            locked: false,
            classes: 'startNode',
            position: {
              x: evt.position.x,
              y: evt.position.y
            },
            style: { 'shape': 'ellipse' }
          });
          setNodeArray([...nodeArray, props.nodeType])

          props.stopAddNode("");
        } else {
          alert("Start Node exist");
        }

      } else if (props.nodeType == "endNode") {

        if (controlEndState == -1) {
          var evtTarget = evt.target;
          if (evtTarget === cyRef.current) {
            // console.log('tap on background');

            cyRef.current.add({
              group: 'nodes',
              data: {
                weight: 5,
                label: props.nodeType,
              },
              classes: 'endNode',
              position: {
                x: evt.position.x,
                y: evt.position.y
              },
              style: { 'shape': 'ellipse' }
            });
            setNodeArray([...nodeArray, props.nodeType])

          }
          props.stopAddNode("");
        } else {
          alert("End Node exist");
        }


      } else if (props.nodeType == "activity") {
        var evtTarget = evt.target;
        if (evtTarget === cyRef.current) {
          // console.log('tap on background');

          cyRef.current.add({
            group: 'nodes',
            data: {
              weight: 5,
              label: props.nodeType,
            },
            classes: 'rectangleNode',
            position: {
              x: evt.position.x,
              y: evt.position.y
            },
            style: {
              // 'shape': 'barrel',
              // "width": "80",
            }
          });
          setNodeArray([...nodeArray, props.nodeType])

        }
        props.stopAddNode("");
      }
    } else {
      // console.log('tap on some element');
    }


  }

  return (
    <div>
      <CytoscapeComponent
        elements={elements}
        // layout={layout}
        cy={cy => {
          cyRef.current = cy;

          cyRef.current.unbind("tap"); // unbind event to prevent possible mishaps with firing too many events
          cyRef.current.unbind('mousedown');          // unbind event to prevent the event to fire 

          cyRef.current.bind("tap", addNode);
          cyRef.current.bind('mousedown', mousedownEvent);
        }}
        stylesheet={styleSheet}
        style={{
          width: "100%",
          height: "83vh",
          border: '1px solid black'
        }}
      />
    </div>
  );
};

export default NewComponent;

标签: reactjscytoscape.jscytoscape

解决方案


推荐阅读