带有箭头的 React-konva 双连接对象

React-konva double connected objects with arrow

我正在尝试通过允许两个节点(Circle class 的形状)被双重引用(A 通过 [=11= 连接到 B)来扩展 Connected Objects 演示] 并且 B 通过 Arrow2) 连接到 A)。我使用 react-konva 包。

我已经在 Code Sandbox 上实现了一个具有一些基本功能的演示。

在第 56 行你会找到节点信息,在第 21 行有一个高阶组件,它根据起始节点和结束节点位置。

在默认示例中,箭头按预期工作。如果您尝试将 redNode.x 的值设置为 300,则箭头重叠。当 blueNode.x 等于 -100 时也会发生同样的情况。这与我计算箭头的方式有关(我怀疑行 38 上的方程式)。

另请注意,当 redNode.x 移动到值 300 时,两个箭头相互接近(这也发生在其他值上),这是我不希望发生的事情。我希望当两个节点改变位置并且不重叠或相互接近时,箭头具有相同的形状。不幸的是,我缺乏数学并不能帮助我解决问题。我还尝试使用 quadraticCurveTo 方法创建自定义形状但没有成功。

在此先感谢您的帮助。我感谢所有解决方案。

制作曲线的方法有很多种。这是我试图让它变得更好的尝试:

import React from "react";
import ReactDOM from "react-dom";
import { Stage, Layer, Circle, Arrow, Text } from "react-konva";

const BLUE_DEFAULTS = {
  x: 100,
  y: 100,
  fill: "blue",
  width: 30,
  height: 30,
  draggable: true
};

const RED_DEFAULTS = {
  x: 100,
  y: 300,
  fill: "red",
  width: 30,
  height: 30,
  draggable: true
};

const Edge = ({ node1, node2 }) => {
  const dx = node1.x - node2.x;
  const dy = node1.y - node2.y;
  let angle = Math.atan2(-dy, dx);

  const radius = 20;
  const curvePower = 30;

  const arrowStart = {
    x: node2.x + -radius * Math.cos(angle + Math.PI),
    y: node2.y + radius * Math.sin(angle + Math.PI)
  };

  const arrowEnd = {
    x: node1.x + -radius * Math.cos(angle),
    y: node1.y + radius * Math.sin(angle)
  };

  const arrowCurve = {
    x:
      (arrowStart.x + arrowEnd.x) / 2 +
      curvePower * Math.cos(angle + Math.PI / 2),
    y:
      (arrowStart.y + arrowEnd.y) / 2 +
      curvePower * Math.sin(angle - Math.PI / 2)
  };

  return (
    <Arrow
      tension={0.2}
      points={[
        arrowStart.x,
        arrowStart.y,
        arrowCurve.x,
        arrowCurve.y,
        arrowEnd.x,
        arrowEnd.y
      ]}
      stroke="#000"
      fill="#000"
      strokeWidth={3}
      pointerWidth={6}
    />
  );
};

const App = () => {
  const [blueNode, updateBlueNode] = React.useState(BLUE_DEFAULTS);
  const [redNode, updateRedNode] = React.useState(RED_DEFAULTS);

  return (
    <Stage width={window.innerWidth} height={window.innerHeight}>
      <Layer>
        <Text text="Drag any node to see connections change" />
        <Edge node1={blueNode} node2={redNode} />
        <Edge node1={redNode} node2={blueNode} />
        <Circle
          {...blueNode}
          onDragMove={e => {
            updateBlueNode({ ...blueNode, ...e.target.position() });
          }}
        />
        <Circle
          {...redNode}
          onDragMove={e => {
            updateRedNode({ ...redNode, ...e.target.position() });
          }}
        />
      </Layer>
    </Stage>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

演示:https://codesandbox.io/s/react-konva-double-connected-objects-m5g22