4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

LeaderLineというHTML要素同士に線を引けるライブラリを使ってみる。(React × TypeScript)

Last updated at Posted at 2021-06-14

概要

Webページ内の情報を線で結ぶことがしたいので該当技術を色々探していた。
Webページ内の情報全てをSVGにしてしまう方法などが考えられたが、設定すべきパラメータが多くなることが考えられたので、こちらも辞めた。

SVGを埋め込むようなことが出来るらしいが、調査していくと新しく理解することが多くなったので、既存のライブラリ(LeaderLine)で簡単に実現することにした。

以下では、自分が実装した範囲での実用例を中心に示していきます。

LeaderLineのサンプル
leader_line_sample.png

前置き

普段は自然言語処理を少しやる大学院生で、必要に応じてTypeScript, JavaScript, Reactを使用しているため誤用や実装上の不備が多く見られるかもしれません。この記事に有用性を感じて、それらについてご指摘を頂いた場合には出来る限り更新するよう考えています。

本記事は初学者の立場として、参考に出来るものが少なかったのでメモとして残しています。

LeaderLineについて

TypeScriptで利用するためにTypeが必要になるのですが、leader-lineでは対応していなく、leader-line-newという方を用いる必要があります。

要素を線で結べるらしい方法はいくつかまとめられていたので、こちらの記事で問題が解決できなかった場合には参照してみて下さい。

参照:JSで要素間を線で繋いだり動かしたりライブラリ調査@202002 - Qiita

とりあえず使ってみる(JavaScript)

JavaScriptでとりあえず使ってみる。

sample1.html
<!DOCTYPE html>
<head>
    <script src="anseki-leader-line-fc2bfda\leader-line.min.js"></script>
    <style type="text/css">
        html{
            margin: auto;
        }
        .main_comment{
            display: inline-block;
        }
        .comments{
            display: inline-block;
        }
        .main_comment{
            width: auto;
            margin: 5rem;
            border: 5px solid tomato;
        }
        .comment{
            width: auto;
            margin: 1rem;
            border: 5px solid turquoise
        }
        </style>
</head>
<body>
    <div class="map">
        <div class="main_comment" id="mc1">メインコメント</div>
        <div class="comments">
            <div class="comment" id="c1">コメント1</div>
            <div class="comment" id="c2">コメント2</div>
        </div>
    </div>
    <script>
        new LeaderLine(
            document.getElementById("mc1"),
            document.getElementById("c1")
            );
        new LeaderLine(
            document.getElementById("mc1"),
            document.getElementById("c2")
        )
    </script>
</body>

表示すると下記画像のようなものができます。
htmlファイルを表示したものをデベロッパーツールなどで見ていただくとsvgで色々やってくれているのが分かるかと思います。

sample1.htmlの結果
sample1.png

React × TypeScriptでやってみる

まず、Reactのプロジェクトを雛形を利用して作成する。
参照:create-react-appで React + Typescript な環境を構築する - Qiita

実行環境
node: v14.5.0
create-react-app: 3.4.1

create-react-app {プロジェクト名} --typescript

プロジェクト名をll_sampleとして、

例)
create-react-app ll_sample --typescript

※もしかしたら@types/reactに欠損があるかもしれないので、import React from "react"の部分で怒られていたら下記を実行してみてください。

npm install @types/react

上記で述べたようにleader-line-newをライブラリとして用います。cd ll_sampleで移動してから、

npm install leader-line-new

混乱が生じないように、作成されるApp.tsxについて変更を加えて、機能を把握することを行っていきます。

App.tsx
import React, {useEffect, useState} from 'react';
import './App.css';
import LeaderLine from "leader-line-new";

const App: React.FC = () => {
  // initialLinksで初期化
  const initialLinks: LeaderLine[] = [];
  const [links, setLinks] = useState(initialLinks);
  
  const [link_number, setLinknumber] = useState(0);
  const [num, setNum] = useState(3);

  useEffect(() =>{
    // removeしなければリンク表示が残ったままである
    if (links.length > 0){
      links.filter(l => {
        l.remove();
      })
    }
    let link_id: number = Math.floor(link_number % num);
    let start = document.getElementById("mc_0");
    let end = document.getElementById(String(link_id));

    if (start && end){
      let link = [];
      link.push(new LeaderLine(start, end, {startSocket:"right", endSocket:"left"}));
      setLinks(link);
    }

  },[link_number]);

  // クリックされたら動くfunction
  // setLinknumberでリンク先を変更する
  const handleOnclick = () =>{
    setLinknumber(link_number+1);
  }

  return(
    <div>

      <div className="area">

        <div className="main_comment_area">
          <div className="main_comment" id="mc_0">
            メインコメント
          </div>
          <button onClick={handleOnclick}>リンク先変更</button>
        </div>

        <div className="comments">
          {
            (()=>{
              let comments = [];
              for (let i=0; i<num; i++){
                comments.push(
                  <div className="comment" id={String(i)}>
                    コメント{i}
                  </div>
                )
              }
              return comments;
            })()
          }
        </div>

      </div>

    </div>
  );
}

export default App;

これに伴って、LeaderLineの矢印の表示が見やすくなるように簡単にApp.cssを整えます。

App.css
.area{
  display: flex;
}

.main_comment_area{
  margin: 0 20rem 0 0;
}

.main_comment{
  border: 5px solid tomato;
  margin: 5rem;
}

.comment{
  margin: 1rem;
  border: 5px solid turquoise;
}

この2つを変更することに加えて、index.tsxにおいてimport "./index.css"をコメントアウト等で無効にしておいてください。
ここまで終えたらnpm start等で実行して表示を確認してみて下さい。

初期状態では下記画像のようになっているかと思います。以降ボタン押すことによってhandleOnclickが作動し、その中でlink_numberが変更されることでuseEffectが動きLeaderLineによる描画の変更が行われます。

①初期状態
初期状態.png

②「リンク先変更」ボタンを1回押すと・・・
step2.png

③「リンク先変更」ボタンをもう1回押すと・・・
step3.png

④「リンク先変更」ボタンをさらに1回押すと・・・
初期状態.png

LeaderLineが関係する部分のプログラムの説明

  • l.remove()について
    remove()をしないと、new LeaderLine()で生成された描画が残った状態で引き継がれてしまうので注意が必要。

  • LeaderLine(start, end, {startSocket:"right", endSocket:"left"})について
    startSocket,endSocketはそれぞれ要素のどの位置(top,bottom,right,left)にリンクは接続するのかということをオプションとして設定できるようになっています。
    詳しくは公式ドキュメントを参照してください。

これで、LeaderLineのReact×TypeScriptでの機能確認は終了となります。

最後に

本記事内で「コメント」という単語を使っている通り、レビューコメントに対して処理を施すということを実験的にやりたくてLeaderLineを使用しました。下記リンク先でもLeaderLineをとりあえず使いましたが、表示は今後いろいろ弄る予定です。
レビューコメントを収集してマップ化する機能(いつか公開したい)- GitHub

リンク先のマップ化のやつ
whisky_sample_leader_line_added.png

(早く就活終わらしていろいろやりたい・・・)

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?