React-konva двухсвязные объекты со стрелкой

Я пытаюсь расширить демонстрацию Connected Objects, допустив два узла (формы Circle class) для двойной ссылки (A соединяется с B с помощью Arrow1, а B соединяется с A с помощью Arrow2). Работаю с пакетом react-konva.

Я реализовал демонстрацию Code Sandbox с некоторыми базовыми функциями. .

В строке 5, 6 вы найдете информацию об узлах, в строке 21 существует высокоуровневый компонент, который создает стрелку на основе начальной и конечной позиции узла.

В примере по умолчанию стрелки работают должным образом. Если вы попытаетесь установить значение redNode.x на 300, стрелки перекрываются. То же самое происходит, когда blueNode.x равно -100. Это как-то связано с тем, как я вычисляю стрелки (я подозреваю, что уравнения в строке 38).

Также обратите внимание, что когда redNode.x перемещается к значению 300, две стрелки приближаются друг к другу (это происходит и с другими значениями), чего я не хочу. Я ожидаю, что стрелки будут иметь одинаковую форму, когда два узла меняют положение, а не перекрывать друг друга или приближаться друг к другу. К сожалению, отсутствие у меня математики не помогает мне решить проблему. Я также безуспешно пытался создать нестандартную форму, используя метод quadraticCurveTo.

Заранее спасибо за помощь. Я ценю все решения.


person Charles Nikolopoulos    schedule 23.08.2019    source источник


Ответы (1)


Есть много способов сделать изогнутые линии. Вот моя попытка сделать это лучше:

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

person lavrton    schedule 26.08.2019
comment
Это превосходно! Я хочу спросить вас, как вы научились вычислять эти формулы. Это как-то связано с тригонометрией, но не могли бы вы посоветовать мне несколько книг для начинающих? Что-то вроде практической тригонометрии для HTML-холста. Это тоже хорошая идея для публикации в блоге! - person Charles Nikolopoulos; 27.08.2019
comment
Книг не знаю (наверное, есть). Но идея книги / поста классная, приму во внимание. Просто надо выучить скучную математику. - person lavrton; 27.08.2019