[BaklavaJS] web上でノードを操作する [Vue.js]

# はじめに
どうも、visual programmingに興味を持ち始めた人です。

この記事では、そんなvisual programmingがvue.js上でできるようになるライブラリを紹介します。

# BaklavaJSの紹介

https://newcat.github.io/baklavajs/#/

https://github.com/newcat/baklavajs

> BaklavaJSは、Web用のグラフ/ノードエディターです。カスタムノードを作成する機能とともに、使いやすいエディターを提供します。さらに、それは拡張性に重点を置いており、それが多用途のプラグインシステムにつながります。型の安全性を保証するために、BaklavaJSエコシステム全体がTypeScriptで記述されています。

# 使い方
Vue.jsを使って`BaklavaJS`を使っていきます。

Vue.jsを用意します。

## インストール
Baklavaをインストールしていきます。

```bash
C:\> npm i baklavajs
```

次に、プラグインとして登録します。

## Example

```javascript:main.js
import { BaklavaVuePlugin } from "@baklavajs/plugin-renderer-vue";
import "@baklavajs/plugin-renderer-vue/dist/styles.css";

Vue.use(BaklavaVuePlugin);
```

↑これを`[main.js]`に追加します。
そして、
↓このコードで`HelloWorld.vue`で上書きします。

```vuejs:HelloWorld.vue
<template>
  <baklava-editor :plugin="viewPlugin"></baklava-editor>
</template>

<script>
import { Editor, NodeBuilder } from '@baklavajs/core'
import { ViewPlugin } from '@baklavajs/plugin-renderer-vue'

export default {
  data () {
    return {
      editor: new Editor(),
      viewPlugin: new ViewPlugin()
    }
  },
  created () {
    this.editor.use(this.viewPlugin)
    this.createNode()
  },
  methods: {
    createNode () {
      const inputNode = new NodeBuilder('Input')
        .addInputInterface('Input')
        .build()
      const outputNode = new NodeBuilder('Output')
        .addOutputInterface('Output')
        .build()
      this.editor.registerNodeType('Input', inputNode)
      this.editor.registerNodeType('Output', outputNode)
    }
  }
}
</script>

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/eb105768-a141-077a-f5e9-2c93947240b9.png)
これで簡単なインターフェースはできました。

### コードの解説

```javascript
this.editor.use(this.viewPlugin)
```

↑これでノードの読み書きができるようになります。

```javascript
this.createNode()
```

↑これで、ノードがインターフェース上で使えるようになります。

```javascript
const inputNode = new NodeBuilder('Input')
  .addInputInterface('Input')
  .build()
const outputNode = new NodeBuilder('Output')
  .addOutputInterface('Output')
  .build()
```

これでノードのデータを作成しています。
`.addInputInterface`でデータをインプットできるようになり、
`.addOutputInterface`でデータをアウトプットできるようになります。

### ノードの作成
ここで、右クリックをし、**[Add Node]**を押すと、作成したノード一覧が出てきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/d43d1d9b-7659-a9d2-ad37-21318bb79a8e.png)


# ノードにオプションを加える

## 事前準備
インターフェースを作成したファイルの`<script>`内の上の方にに以下のコードを追加します。

```diff_javascript:HelloWorld.vue
...
import { Editor, NodeBuilder } from '@baklavajs/core'
import { ViewPlugin } from '@baklavajs/plugin-renderer-vue'
+ import { OptionPlugin } from '@baklavajs/plugin-options-vue'
+ import { Engine } from '@baklavajs/plugin-engine'
...
```

次に、追加したライブラリをインターフェースに登録していきます。

```diff_javascript:HelloWorld.vue
...
export default {
  data () {
    return {
      editor: new Editor(),
      viewPlugin: new ViewPlugin(),
+     engine: new Engine(true)
    }
  },
  created () {
+   this.editor.use(new OptionPlugin())
+   this.editor.use(this.engine)
    this.editor.use(this.viewPlugin)
    this.createNode()
  }
...
```

```javascript
this.editor.use(new OptionPlugin())
```

↑これでノードのオプションを利用できるようになります。

```javascript
this.editor.use(this.engine)
```

↑これでノードの中身を動的に変更できる`calculate`という機能を利用できるようになります。

## 新しいノードの作成

公式サンプルにあったノード二つを作っていきます。

まず、`components`フォルダの中にノードを入れるための`node`フォルダを作成します
次に、[`MathNode.js`]と[`DisplayNode.js`]をnodeフォルダの中に作成します。
MathNode.jsには上のコードを、
DisplayNode.jsには下のコードを入れてください。

```javascript:MathNode.js
import { NodeBuilder } from '@baklavajs/core'

export const MathNode = new NodeBuilder('MathNode')
  .setName('Math')
  .addInputInterface('Number 1', 'NumberOption', 1)
  .addInputInterface('Number 2', 'NumberOption', 10)
  .addOption('Operation', 'SelectOption', 'Add', undefined, {
    items: ['Add', 'Subtract']
  })
  .addOutputInterface('Result')
  .onCalculate((n) => {
    const n1 = this.getInterface('Number 1').value
    const n2 = this.getInterface('Number 2').value
    const operation = this.getOptionValue('Operation')
    let result
    if (operation === 'Add') {
      result = n1 + n2
    } else if (operation === 'Subtract') {
      result = n1 - n2
    }
    this.getInterface('Result').value = result
  })
  .build()
```

```javascript:DisplayNode.js
import { NodeBuilder } from '@baklavajs/core'

export const DisplayNode = new NodeBuilder('DisplayNode')
  .setName('Display')
  .addInputInterface('Value')
  .addOption('ValueText', 'TextOption')
  .addOption('Test', 'InputOption')
  .onCalculate(n => {
    let value = n.getInterface('Value').value
    if (typeof value === 'number') {
      value = value.toFixed(3)
    }
    n.setOptionValue('ValueText', value)
  })
  .build()
```

## ノードの登録

上で作成したノードをインターフェースに登録していきます。

```diff_javascript:HelloWorld.vue
  ...
import { OptionPlugin } from '@baklavajs/plugin-options-vue'
import { Engine } from '@baklavajs/plugin-engine'
+ import { MathNode } from './node/MathNode'
+ import { DisplayNode } from './node/DisplayNode'

export default {
  ...
  methods: {
    createNode () {
      ...
      this.editor.registerNodeType('Input', inputNode)
      this.editor.registerNodeType('Output', outputNode)
+     this.editor.registerNodeType('MathNode', MathNode)
+     this.editor.registerNodeType('DisplayNode', DisplayNode)
    }
  }
}
```

↑これで、ノードの登録が完了しました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/f1dd06d1-f434-c277-6b8e-dfbdbd6b2f04.png)

このように、さっきは無かったノードが追加されています。

# さいごに

vue.jsを使ってvisual programingができるライブラリ、[BaklavaJS]を紹介しました。

マイナーなライブラリなので、情報は少ないですが、少し触ってみた感じ、いろいろと応用が利きそうです。


***以上***