[React] Leader Line で要素同士を線でつないでみる | 心を無にして始める React

準備

Leader Line

Draw a leader line in your web page.

https://anseki.github.io/leader-line/

こちらの React版 です。

https://github.com/II-alex-II/leader-line-new

LeaderLine のインストール

npm i leader-line-new

使ってみる

Leader Line はきれいに曲線がでたりするので、オーバーフローでヘルプ機能とかできたらかっこいいかも (*’▽’)

イメージ

局所的なサンプル

const elem1 = elem1Ref.current;
const elem2 = elem2Ref.current;

const line = new LeaderLine(
  LeaderLine.areaAnchor({ element: elem1, color: '#db5879', radius: 10, dash: true }),
  LeaderLine.areaAnchor({ element: elem2, color: '#db5879', radius: 10, dash: true }),
  {
    endLabel: LeaderLine.pathLabel('>>>>>'),
    path: 'fluid',
    size: 3,
    color: '#00d8ff',
    gradient: {
      startColor: '#ffc10780',
      endColor: '#ffc107',
    },
    startSocket: "right",
    endSocket: "left",
    endPlug: 'hand',
    endPlugSize: 1,
  }
);

サンプル

上のイメージを出すときに使ったものです。

例によって、App.js を編集します。

線のバリエーションをお試ししやすいように、コメントアウトしたものもすこし残します。

import { useEffect, useRef } from 'react';
import LeaderLine from "leader-line-new";

import './App.css';

function App() {

  const elem1Ref = useRef(null);
  const elem2Ref = useRef(null);

  useEffect(() => {
    if (elem1Ref === null || elem2Ref === null) {
      return;
    }

    const elem1 = elem1Ref.current;
    const elem2 = elem2Ref.current;

    const line = new LeaderLine(
      LeaderLine.areaAnchor({ element: elem1, color: '#db5879', radius: 10, dash: true }),
      LeaderLine.areaAnchor({ element: elem2, color: '#db5879', radius: 10, dash: true }),
      {
        endLabel: LeaderLine.pathLabel('>>>>>'),
        // path: 'straight',
        // path: 'arc',
        path: 'fluid',
        // path: 'magnet',
        // path: 'grid',
        size: 3,
        color: '#00d8ff',
        gradient: {
          startColor: '#ffc10780',
          endColor: '#ffc107',
        },
        startSocket: "right",
        endSocket: "left",
        // startPlug: 'disc', // disc, squeare, arrow1, arrow2, arrow3, hand, crosshair, behind
        // startPlugSize: 2,
        endPlug: 'hand',
        endPlugSize: 1,
        // dash: {
        //   animation: {
        //     duration: 800,
        //     timing: "ease-out"
        //   }
        // },
      }
    );

    window.dispatchEvent(new Event('resize'));
    return () => line.remove();
  }, [])

  return (
    <div className="p-5 bg-dark" style={{ minHeight: '100vh' }}>
      <div ref={elem1Ref} className="m-5 p-5 bg-warning" id="id-1" style={{ width: 64 }} />
      <div ref={elem2Ref} className="m-5 p-5 bg-primary ms-auto" id="id-2" style={{ width: 64 }} />
    </div>
  );
}

export default App;

はい、できました。

トラブルシュート

初回の表示で、線が要素からずれて表示されてしまう

Chrome でみていると、ブラウザが最初に表示したときの要素の座標計算が少しずれているようでした。
内部的にスクロールバーがある前提で計算がされているようで、中央寄せや右寄せにしたときに特に顕著になります。

そのため、スマホやタブレットでの表示では、この現象はおきません。

ライブラリ側での対応待ちでもよいと思いますが、この記事を書いている時点でリポジトリの更新が約2年ないため、暫定対処で切り抜けるのが良いと考えました。

解決策① 非推奨

スクロールバーを常に出しておきます(笑)

これでもいちおうずれはなくなりますが、お勧めはしません (笑)

overflow-y: scroll;

解決策② 推奨!

Resizeイベントを疑似的に発行します(発火させます)。

JQuery では object.resize() で発火できますが、JavaScript だとこんな感じです。

window.dispatchEvent(new Event('resize'));

この記事のサンプルのほうには、すでに記載してあります (/・ω・)/