m's blog

備忘録とかメモとか

【Neo4j】Dockerで試すNeo4j【第6回/JavaScript編 その3】

【Neo4j】Dockerで試すNeo4j【第6回/JavaScript編 その3】

今回は、「Dockerで試すNeo4j」シリーズの最終編となります。

ここまで構成・実装した環境とコードを使って、登録されたPersonFOLLOWリレーションをグラフ表示してみたいと思います。

↓ 「Dockerで試すNeo4j」シリーズ記事一覧はこちら

目次

はじめに

今回の記事では、以下の記事で追加したデータを使用します。

データを追加していない場合は、上記の記事を参考にデータを追加してください。

注意事項

トライアルという事で、クライアントからNeo4jにアクセスしていますが、アプリを公開する場合などはサーバ経由でアクセスするようにするなど、調整してください。

構成

解説を進める前に、最終的なファイル構成を紹介しておきたいと思います。

最終的なファイル構成は、以下のようになります。

【Neo4j】Dockerで試すNeo4j【第6回/JavaScript編 その3】

ここまでの記事で紹介した構成と同じもので、特にファイルの追加や変更をしない、publicなどのディレクトリの中身は表示していません。

必要なパッケージのインストール

まずは、今回の記事で必要になるパッケージを追加します。

グラフ表示には、Cytoscape.jsを使用します。

以下のコマンドで、cytoscapeをインストールしてください。

yarn add cytoscape

グラフ描画関数を追加

それでは、早速、フォロー検索の結果をグラフで表示するコードを追加していきます。

まずは、グラフ描画処理の部分を関数renderGraphにまとめておきます。

src/packages/Graph/renderGraph.tsファイルを追加して、以下のようなコードを追加してください。

import { Elements } from "../@types/App";
import cytoscape, { Core } from "cytoscape";

export const renderGraph = (elementId: string, elements: Elements): Core => {
    const style = [
        {
            selector: 'node[label = "Person"]',
            css: {
                'background-color': '#6FB1FC',
                content: 'data(name)',
                'font-size': '4rem',
                width: 3,
                height: 3,
                color: 'data(color)',
            },
        },
        {
            selector: 'edge',
            css: {
                content: 'data(relationship)',
                width: 0.2,
                'font-size': '3rem',
                'curve-style': 'bezier',
                'target-arrow-shape': 'triangle',
                'arrow-scale': 0.2,
                color: '#a5a5a5',
            },
        },
    ]

    const layout = {
        name: 'cose',
        componentSpacing: 1000,
    }

    return cytoscape({
        container: document.getElementById(elementId),
        elements: elements,
        style: style,
        layout: layout,
    })
}

ここで、1つ目の引数elementIdは描画先HTMLタグのidです。

2つ目の引数elementsは、前回記事のフォロー検索で生成される、グラフ表示用のデータです。

関数の最後のcytoscape関数により、idelementIdであるHTMLタグに、elementsデータがグラフ表示されます。

また、stylelayoutで指定されたスタイル、レイアウトのグラフが描画されます。

グラフ表示コンポーネントを追加

続いて、グラフ表示用のコンポーネントGraphを定義しておきます。

src/packages/Graph/Graph.tsxファイルを追加して、以下のように記述してください。

import React, { useEffect } from "react";
import { Elements } from "../@types/App";
import { renderGraph } from "./renderGraph";

type Props = {
    elements: Elements
}

export default function Graph({ elements }: Props) {
    const ELEMENT_ID_FOR_GRAPH = 'graph'

    useEffect(() => {
        renderGraph(ELEMENT_ID_FOR_GRAPH, elements)
    }, [elements])

    const cyStyle = {
        height: '80vh',
        width: '98vw',
    }

    return <div id={ELEMENT_ID_FOR_GRAPH} style={cyStyle}/>
}

ここで、cyStyleはグラフの表示サイズを調整しています。

ELEMENT_ID_FOR_GRAPHはグラフを表示させるHTMLタグのidです。

以下の部分では、プロパティelementsが更新されるたびに、先ほど追加したrenderGraph関数が呼び出されて、グラフが再描画されます。

    useEffect(() => {
        renderGraph(ELEMENT_ID_FOR_GRAPH, elements)
    }, [elements])

useEffectの第二引数[elements]の部分により、elementsが更新されるたびに、第一引数のコールバックが呼び出されます。

仕上げ

最後に、src/App.tsxを調整して、ここまでのコードを反映させます。

前回記事で、elementsの内容をリストで表示していた部分を、先ほど追加してGraphコンポーネントで置き換えます。

以下のように、src/App.tsxを書き換えてください。

import React, { useEffect, useState } from 'react';
import { Elements, Node } from "./packages/@types/App";
import Graph from "./packages/Graph/Graph";
import { getAllPersons } from "./packages/Search/getAllPersons";
import Search from "./packages/Search/Search";

function App() {
    const [elements, setElements] = useState<Elements>({ nodes: [], edges: [] })
    const [persons, setPersons] = useState<Node<any>[] | []>([])

    useEffect(() => {
        (async () => setPersons(await getAllPersons()))()
    }, [])

    return (
        <div>
            <div>
                <Search persons={persons} handleSearchButtonClick={(elements) => setElements(elements)}/>
            </div>
            <div>
                <Graph elements={elements}/>
            </div>
        </div>
    )
}

export default App;

前述のとおり、変更箇所はGraphコンポーネントの置き換えのみです。

動作確認

コードが完成したので、実際に動かして動作を確認し、シリーズの締めとしたいと思います。

以下のコマンドで、Reactアプリをスタートしてください。

yarn start

アプリを起動したら、http://localhost:3000/にアクセスしてください。

全ての「FOLLOW」リレーションを検索

まずは、ターゲット入力なしでの表示をチェックしてみます。

ページ左上の方に「Search」ボタンが表示されていると思うので、ターゲットには何も入力せずに「Search」ボタンを押してみてください。

ボタンをクリックすると、以下のようなグラフが表示されると思います。

【Neo4j】Dockerで試すNeo4j【第6回/JavaScript編 その3】

これは、全てのFOLLOWリレーションをグラフ化したものになります。

ターゲットを指定したフォロー検索

続いて、ターゲットを指定した検索を試してみたいと思います。

ターゲット入力欄で「Ichiro」を選択、または入力して、「Search」ボタンをクリックしてください。

すると、以下のようなグラフが表示されると思います。

【Neo4j】Dockerで試すNeo4j【第6回/JavaScript編 その3】

前回記事では、解説を省略しましたが、ターゲットは「赤」文字で、ターゲットから始まるフォローの流れのノードは「緑」の文字で表示されます。

また、ターゲットで終わるフォローの流れのノードは「青」文字で表示されます。

ターゲットで終わるフォローの流れを確認するため、ターゲット入力欄に「Taro」と入力して再度検索してみてください。

すると、以下のようなグラフが表示されます。

【Neo4j】Dockerで試すNeo4j【第6回/JavaScript編 その3】

ターゲット「Taro」に向かうフォローの流れにあるノードが「青」文字で表示されているのが確認できます。

ここで、「Saburo」にはターゲット「Taro」からのフォローもありますが、文字色は「ターゲットに向かうフォローの流れ」を優先させているため、「青」文字で表示されています。

サンプルコード

以下のリポジトリに「Dockerで試すNeo4j」シリーズ全話分のコードを設置しています。

うまく動かない場合は、上記のリポジトリをクローンして試してみてください。

まとめ

以上、全6回にわたって、DockerとNeo4j、そしてReactを使用してNeo4jを試してみました。

複雑なリレーションを扱う場合、Neo4j非常に便利なツールだと感じました。

がっつりサービスのベースとなるデータベースとしてNeo4j使うのもいいと思いますが、Dockerと併せて、ちょっとしたツールとして使うのもありかなと思います。

ぜひ一度、Neo4jを試してみてください。

↓ 「Dockerで試すNeo4j」シリーズ記事一覧はこちら