カスタムエッジ

カスタムノードと同様に、React Flowのカスタムエッジの一部は単なるReactコンポーネントです。つまり、エッジに沿って何でもレンダリングできます!このガイドでは、いくつかの追加コントロールを使用してカスタムエッジを実装する方法を示します。

基本的なカスタムエッジ

エッジが接続された2つのノード間のパスをレンダリングしない場合、それはあまり役に立ちません。これらのパスは常にSVGベースであり、通常は<BaseEdge />コンポーネントを使用してレンダリングされます。実際にレンダリングするSVGパスを計算するために、React Flowには便利なユーティリティ関数がいくつか用意されています。

カスタムエッジの開始として、ソースとターゲット間の直線パスをレンダリングします。

import { BaseEdge, getStraightPath } from '@xyflow/react';
 
export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) {
  const [edgePath] = getStraightPath({
    sourceX,
    sourceY,
    targetX,
    targetY,
  });
 
  return (
    <>
      <BaseEdge id={id} path={edgePath} />
    </>
  );
}

カスタムエッジコンポーネントに渡されるすべてのプロップは、EdgeProps型の下のAPIリファレンスにあります。

これにより、デフォルトの"straight"エッジタイプと同じ動作をする直線エッジが得られます。それを使用するには、<ReactFlow />コンポーネントのedgeTypesプロップも更新する必要があります。

edgeTypesオブジェクトは、コンポーネントの外側で定義するか、ReactのuseMemoフックを使用して、不要な再レンダリングを防ぐことが重要です。これを行うのを忘れると、React Flowはコンソールに警告を表示します。

import ReactFlow from '@xyflow/react'
import CustomEdge from './CustomEdge'
 
 
const edgeTypes = {
  'custom-edge': CustomEdge
}
 
export function Flow() {
  return <ReactFlow edgeTypes={edgeTypes} ... />
}

edgeTypesオブジェクトを定義した後、エッジのtypeフィールドを"custom-edge"に設定することで、新しいカスタムエッジを使用できます。

export default function App() {
  const data: string = "world"

  return <h1>Hello {data}</h1>
}

読み取り専用

エッジラベルの追加

カスタムエッジのより一般的な用途の1つは、エッジのパスに沿っていくつかのコントロールまたは情報をレンダリングすることです。React Flowでは、それをエッジラベルと呼びますが、エッジパスとは異なり、エッジラベルは任意のReactコンポーネントにすることができます!

カスタムエッジラベルをレンダリングするには、<EdgeLabelRenderer />コンポーネントでラップする必要があります。これはパフォーマンス上の理由から必要です。エッジラベルレンダラーは、すべてのエッジラベルがレンダリングされる単一コンテナへのポータルです。

接続されているエッジを削除するために使用できるボタンをカスタムエッジに追加してみましょう。

import {
  BaseEdge,
  EdgeLabelRenderer,
  getStraightPath,
  useReactFlow,
} from '@xyflow/react';
 
export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) {
  const { setEdges } = useReactFlow();
  const [edgePath] = getStraightPath({
    sourceX,
    sourceY,
    targetX,
    targetY,
  });
 
  return (
    <>
      <BaseEdge id={id} path={edgePath} />
      <EdgeLabelRenderer>
        <button
          onClick={() => setEdges((edges) => edges.filter((e) => e.id !== id))}
        >
          delete
        </button>
      </EdgeLabelRenderer>
    </>
  );
}

ここでこのエッジを使用しようとすると、ボタンがフローの中央にレンダリングされていることがわかります(「ノードA」の後ろに隠れている可能性があります)。エッジラベルポータルのため、ボタンを自分で配置するために追加の作業を行う必要があります。

A screen shot of a simple flow. The edge label renderer is highlighted in the DOM inspector and the button is rendered in the centre of the flow.

幸いなことに、既に見たパスユーティリティがこれの助けになります!レンダリングするSVGパスとともに、これらの関数はパスの中点のx座標とy座標も返します。次に、これらの座標を使用して、カスタムエッジラベルを正しい位置に移動できます!

export default function CustomEdge({ id, sourceX, sourceY, targetX, targetY }) {
  const { setEdges } = useReactFlow();
  const [edgePath, labelX, labelY] = getStraightPath({ ... });
 
  return (
    ...
        <button
          style={{
            position: 'absolute',
            transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
            pointerEvents: 'all',
          }}
          className="nodrag nopan"
          onClick={() => {
            setEdges((es) => es.filter((e) => e.id !== id));
          }}
        >
    ...
  );
}

エッジラベルがインタラクティブであり、プレゼンテーションのためだけではないことを確認するために、ラベルのスタイルにpointer-events: allを追加することが重要です。これにより、ラベルをクリック可能になります。

カスタムノードのインタラクティブなコントロールと同様に、マウスイベントがキャンバスを制御するのを防ぐために、ラベルにnodragクラスとnopanクラスを追加することを忘れないでください。

更新されたカスタムエッジを使用したインタラクティブな例を次に示します。削除ボタンをクリックすると、そのエッジがフローから削除されます。新しいエッジを作成すると、カスタムノードが使用されます。

export default function App() {
  const data: string = "world"

  return <h1>Hello {data}</h1>
}

読み取り専用