ノードベース フローチャートライブラリーのSvelte Flowを触ってみました！

:::note info
これは [Svelte AdventCalendar 2024](https://qiita.com/advent-calendar/2024/svelte) 18日目の記事です。
昨日は @oekazuma さんによる [なぜSvelteKitのルーティングファイルには+がついているのか？](https://qiita.com/oekazuma/items/0a18f043a70cf5f34567) でした。
:::

## はじめに
ノードベースのフローチャートについて、最近は特に結構見かけることがあるのではと思います
例えば、[マインドマップ](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%A4%E3%83%B3%E3%83%89%E3%83%9E%E3%83%83%E3%83%97)が代表的ですね
あとはノーコードで設定を作っていくアプリケーション（例えば[Unirial Engineのブループリント](https://dev.epicgames.com/documentation/ja-jp/unreal-engine/introduction-to-blueprints-visual-scripting-in-unreal-engine)）があるかと思います

自分で作るとすごく大変そうなのですが、ライブラリーがあれば使い所はあるのかなあ…と思い、触ってみた次第です

## デモ

早速ですが作ったデモです
元は[Threlte]()(svelteのThree.jsラッパーライブラリ)のデモだったものを[Maplibre](https://maplibre.org/maplibre-gl-js/docs/)のデモに書き換えたものです
ノードの切り離しや付け替えが出来ないので、ノードベースである意味が半分以上無いようなデモなのですが、そこは後ほど考えるということで…
（そして実はMapのプロパティ変更でかなりハマっていたのですが、Maplibreについては別の記事で書こうと思います）
![Kapture 2024-12-18 at 10.45.04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2788/723d7d48-0760-b648-04c5-1fc241ede256.gif)

https://svelte-flow-demo.vercel.app/

https://github.com/northprint/svelte-flow-demo

## Svelte Flow概要

[xyflow](https://xyflow.com/)というチームがあり、最初はReact用のReact Flowから始まっているようですが、Svelte用のライブラリーが追加されたという経緯のようです

https://svelteflow.dev/

（このページ、実はNext.js製になっています、少し残念）

ベーシックな実装は以下のとおりです（これは公式ドキュメントそのままでコメントを日本語にしたものです）

``` svelte
<script lang="ts">
  import { writable } from 'svelte/store';
  import { SvelteFlow, Controls, Background, BackgroundVariant, MiniMap } from '@xyflow/svelte';

  // スタイルのインポートが必要です
  // 基本的なスタイルであれば '@xyflow/svelte/dist/base.css'をインポートするだけで十分です
  import '@xyflow/svelte/dist/style.css';

  // ノードとエッジを同期させるために、書き込み可能なwritableとしている
  // ノードをドラッグすると、Svelte Flowは位置を更新する

  // ノードの設定
  const nodes = writable([
    {
      id: '1',
      type: 'input',
      data: { label: 'Input Node' },
      position: { x: 0, y: 0 }
    },
    {
      id: '2',
      type: 'custom',
      data: { label: 'Node' },
      position: { x: 0, y: 150 }
    }
  ]);

  // エッジの設定
  const edges = writable([
    {
      id: '1-2',
      type: 'default',
      source: '1',
      target: '2',
      label: 'Edge Text'
    }
  ]);
</script>

<SvelteFlow {nodes} {edges} fitView on:nodeclick={(event) => console.log('on node click', event)}>
  <Controls />
  <Background variant={BackgroundVariant.Dots} />
  <MiniMap />
</SvelteFlow>
```
ノードと、それをつなぐエッジという構成になっています
（デモの方はノードをコンポーネントに分割しています）
SvelteFlowのコンポーネントにコントロールと作ったノード、エッジを載せるという構成になります
今回ノードとエッジは事前に用意している構成になっていますが、もちろん動的な追加も可能です

## 苦労したところ
- Svelte5に対応していない
    - これがまだ未対応で、イシューやブランチはあるものの、まだしばらくかかりそうな気配です
- TailwindCSSの導入後、CSSの設定を間違えていて、何も表示されなかった
    - app.cssをTailwindのインポートで書き換えてしまったせいで、appに対して、幅と高さが設定されていない状態を作ってしまったのが敗因でした
- TailwindCSSの導入後、Edgeがうまく描画できなかった
    - TailwindCSSの上に基本スタイルを上書きして対応しました
    - おそらく自前でEdgeのスタイルを書く必要があったのだと思います
- Maplibreの罠にハマった
    - SetStyleでBaseMapを更新すると、上に載せているレイヤーがすべてクリアされるのを忘れていて、結構時間食ってしまいました

## まとめ
今回、元々あるデモをそもまま使わせてもらった実装にはなってしまったのですが、ノードに渡すプロパティ周りの実装はもうちょっと考えたい気持ちがあります

UIの引き出しを増やすために使ってみましたが、簡単には行かず、思っていたよりも使いこなすのが大変でした

これを使えばノードベースのUIでやりたいことはほぼすべて実装できそうです
すぐ使えるノードの種類があると良いなあと思いましたが、そこは制作者に一任してカスタマイズさせることに全振りしたようなライブラリーのように感じました

対応が進んでいるSvelte5版に期待しています！（なにか手伝えたらするスタンスではいます）
音とか映像のエフェクトを付けたりする設定画面を作るとかの用途に良いかもしれないなーと思いました