図形をグリグリ動かすためのJSPlumb+ Electron入門

図形をグリグリ動かすためのJSPlumb+ Electron入門

本記事は図形をグリグリ動かせるアプリケーションを作るために図形ライブラリ使ってみたjsplumb編です。

JavaScriptを使っているもののデスクトップアプリケーションを作りたかったのでElectronを使用してます。

図形をグリグリ動かせる!無料JS図形ライブラリ5選比較してみた

図形をグリグリ動かすためのSigma.js+ Electron入門

本記事👉図形をグリグリ動かすためのJSPlumb+ Electron入門

図形をグリグリ動かすためのCytoscape+ Electron入門

図形をグリグリ動かすためのmxGraph+ Electron入門

図形をグリグリ動かすためのD3.js+ Electron入門

今回お試しで作ったやつはこんな感じ

JSPlumbの使い方

Node.jsのインストール

本記事では、electron上で目的のライブラリを動作するため、まずはelectronを動かすうえで必要となるnode.jsをインストールしましょう。

Nodejs – どこでもJavaScriptを使おう

ソースコード

package.json

{
  "name": "sample",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron ."
  },
  "license": "ISC",
  "devDependencies": {
    "electron": "^35.1.4"
  },
  "dependencies": {
    "jsplumb": "^2.15.6"
  }
}

main.js

const { app, BrowserWindow } = require('electron')
const path = require('path')

function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
  
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>jsPlumb Exlample</title>
    <style>
        .window {
            width: 150px;
            height: 100px;
            border: 2px solid #ccc;
            border-radius: 5px;
            padding: 10px;
            position: absolute;
            background: white;
            cursor: move;
        }
        .window.selected {
            border: 2px solid #2196F3;
            background: #E3F2FD;
        }
        #window1 { left: 50px; top: 50px; }
        #window2 { left: 300px; top: 50px; }
        #window3 { left: 175px; top: 200px; }
    </style>
</head>
<body>
    <div id="window1" class="window">Window 1</div>
    <div id="window2" class="window">Window 2</div>
    <div id="window3" class="window">Window 3</div>

    <script src="./node_modules/jsplumb/dist/js/jsplumb.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

script.js

let selectedWindow = null;
let connections = [];

jsPlumb.ready(function() {
    // 基本的な接続設定
    jsPlumb.defaults = {
        connector: "Bezier",
        paintStyle: { stroke: "#456", strokeWidth: 2 },
        endpoint: "Dot",
        anchors: ["Right", "Left"]
    };

    // 初期接続の設定
    setupInitialConnections();

    // ドラッグ可能に設定
    jsPlumb.draggable("window1");
    jsPlumb.draggable("window2");
    jsPlumb.draggable("window3");

    // ウィンドウのクリックイベントを設定
    document.querySelectorAll('.window').forEach(window => {
        // 左クリックで選択
        window.addEventListener('click', function(e) {
            e.stopPropagation();
            selectWindow(this);
        });

        // 右クリックで接続
        window.addEventListener('contextmenu', function(e) {
            e.preventDefault();
            if (selectedWindow && selectedWindow !== this) {
                toggleConnection(selectedWindow, this);
            }
        });
    });

    // ドキュメント全体のクリックで選択解除
    document.addEventListener('click', function() {
        if (selectedWindow) {
            selectedWindow.classList.remove('selected');
            selectedWindow = null;
        }
    });
});

function setupInitialConnections() {
    connections.push(jsPlumb.connect({
        source: "window1",
        target: "window2"
    }));
    connections.push(jsPlumb.connect({
        source: "window2",
        target: "window3"
    }));
    connections.push(jsPlumb.connect({
        source: "window1",
        target: "window3"
    }));
}

function selectWindow(window) {
    if (selectedWindow) {
        selectedWindow.classList.remove('selected');
    }
    selectedWindow = window;
    window.classList.add('selected');
}

function toggleConnection(source, target) {
    const existingConnection = connections.find(conn => 
        (conn.sourceId === source.id && conn.targetId === target.id) ||
        (conn.sourceId === target.id && conn.targetId === source.id)
    );

    if (existingConnection) {
        jsPlumb.deleteConnection(existingConnection);
        connections = connections.filter(conn => conn !== existingConnection);
    } else {
        connections.push(jsPlumb.connect({
            source: source.id,
            target: target.id
        }));
    }
} 

ソースコード解説

基本的なセットアップ

jsPlumbのライブラリを読み込みます。

<script src="./node_modules/jsplumb/dist/js/jsplumb.min.js"></script>

初期化と基本設定

jsPlumb.ready(function() {
    // デフォルト設定
    jsPlumb.defaults = {
        connector: "Bezier",  // 接続線の種類
        paintStyle: { stroke: "#456", strokeWidth: 2 },  // 接続線のスタイル
        endpoint: "Dot",      // エンドポイントの種類
        anchors: ["Right", "Left"]  // 接続点の位置
    };
});

要素のドラッグ可能化

jsPlumb.draggable("window1");
jsPlumb.draggable("window2");
jsPlumb.draggable("window3");

接続の作成

jsPlumb.connect({
    source: "window1",
    target: "window2"
});

接続の削除

jsPlumb.deleteConnection(connection);

実行

ライブラリのインストール

npm install

アプリを実行!

npm start

終わりに

悪くない!が、特筆して良くもない!

jsplumbのデモサイト を見ても思うんですが、これで図形書けるようにするなら他のライブラリ使うか、MermaidのようなText To Imageで作図できるようなツール使うほうが簡単に思えてきちゃいます。

当然、Mermaidの場合は図形をグリグリはできなくなっちゃうんですが・・・。

jsplumbは無料で使える範囲が限られてるので、有料ライセンス版であればもっと有用性が高いかもしれません。

参考

jsplumb

https://github.com/fujarenpaw/codeForBlog/tree/main/code/electron/jsPlumb

本記事で使用したソースコードはGithubにあります。

最新情報をチェックしよう!