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

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

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

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

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

本記事👉​図形をグリグリ動かすためのSigma.js+ Electron入門

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

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

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

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

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

図形をグリグリしたかったんですが、おそらくSigma.jsはできないですね。

デモサイト を見ても図形は動かせなさそうなんですが、作っちゃったので供養として記事にします😭

Sigma.jsの使い方

Node.jsのインストール

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

Nodejs – どこでもJavaScriptを使おう

ソースコード

package.json

{
  "name": "sample",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "license": "ISC",
  "devDependencies": {
    "electron": "^35.1.4"
  },
  "dependencies": {
    "graphology": "^0.26.0",
    "sigma": "^3.0.1"
  }
}

main.js

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

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

  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">
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'">
    <title>Sigma.js Graph Example</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="graph-container"></div>
    <script>
        window.graphology = require('graphology');
        window.sigma = require('sigma');
    </script>
    <script src="./renderer.js"></script>
</body>
</html>

renderer.js

// DOMの読み込み完了を待つ
document.addEventListener('DOMContentLoaded', () => {
    // グラフのインスタンスを作成
    const graph = new graphology.Graph();

    // サンプルノードとエッジを追加
    graph.addNode('1', { 
        x: 0, 
        y: 0, 
        size: 10, 
        label: 'Node 1', 
        color: '#FF6B6B'
    });
    graph.addNode('2', { 
        x: 2, 
        y: 2, 
        size: 10, 
        label: 'Node 2', 
        color: '#4ECDC4'
    });
    graph.addNode('3', { 
        x: -2, 
        y: 2, 
        size: 10, 
        label: 'Node 3', 
        color: '#45B7D1'
    });
    graph.addNode('4', { 
        x: 0, 
        y: 4, 
        size: 10, 
        label: 'Node 4', 
        color: '#96CEB4'
    });

    // エッジを追加
    graph.addEdge('1', '2', { color: '#666' });
    graph.addEdge('1', '3', { color: '#666' });
    graph.addEdge('2', '4', { color: '#666' });
    graph.addEdge('3', '4', { color: '#666' });

    // Sigma.jsのインスタンスを作成
    const container = document.getElementById('graph-container');
    const renderer = new sigma.Sigma(graph, container, {
        minCameraRatio: 0.1,
        maxCameraRatio: 10,
        labelRenderedSizeThreshold: 6,
        labelSize: 12,
        defaultNodeColor: '#999',
        defaultEdgeColor: '#666',
        defaultEdgeSize: 2,
        renderEdgeLabels: true
    });

    // カメラの位置を調整
    const camera = renderer.getCamera();
    camera.setState({
        ratio: 2,
        x: 0,
        y: 0
    });

    // ランダムな色を生成する関数
    function getRandomColor() {
        return '#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0');
    }

    // ノードのクリックイベントを設定
    renderer.on('clickNode', (event) => {
        const node = event.node;
        // 左クリックで色を変更
        graph.setNodeAttribute(node, 'color', getRandomColor());
        renderer.refresh();
    });

    // ノードの右クリックイベントを設定
    renderer.on('rightClickNode', (event) => {
        const node = event.node;
        // 右クリックでサイズを変更
        const currentSize = graph.getNodeAttribute(node, 'size');
        const newSize = currentSize === 10 ? 20 : 10;
        graph.setNodeAttribute(node, 'size', newSize);
        renderer.refresh();
    });

    // マウスホイールでズーム
    renderer.getMouseCaptor().on('wheel', (event) => {
        const factor = event.delta > 0 ? 1.1 : 0.9;
        camera.animatedZoom({ duration: 200, factor });
    });

    // ドラッグでパン
    renderer.getMouseCaptor().on('mousedown', (event) => {
        if (event.originalEvent.button === 0) { // 左クリック
            renderer.getMouseCaptor().on('mousemove', (event) => {
                camera.animate({
                    x: camera.x - event.deltaX / camera.ratio,
                    y: camera.y - event.deltaY / camera.ratio
                }, { duration: 0 });
            });
        }
    });

    // マウスアップでドラッグ終了
    renderer.getMouseCaptor().on('mouseup', () => {
        renderer.getMouseCaptor().off('mousemove');
    });
}); 

ソースコード解説

グラフの初期化とノードの追加

// グラフのインスタンスを作成
const graph = new graphology.Graph();

// サンプルノードを追加
graph.addNode('1', { 
    x: 0, 
    y: 0, 
    size: 10, 
    label: 'Node 1', 
    color: '#FF6B6B'
});
  • graphology.Graph()で新しいグラフインスタンスを作成

  • addNode()メソッドでノードを追加

エッジの追加

// エッジを追加
graph.addEdge('1', '2', { color: '#666' });
  • addEdge()メソッドでノード間の接続を追加

Sigma.jsのレンダリング設定

以下の箇所でsigma.Sigmaインスタンスを作成してグラフを可視化しています。

const renderer = new sigma.Sigma(graph, container, {
    minCameraRatio: 0.1,
    maxCameraRatio: 10,
    labelRenderedSizeThreshold: 6,
    labelSize: 12,
    defaultNodeColor: '#999',
    defaultEdgeColor: '#666',
    defaultEdgeSize: 2,
    renderEdgeLabels: true
});
  • 重要な設定パラメータ:

    • minCameraRatio/maxCameraRatio: ズームの制限

    • labelRenderedSizeThreshold: ラベルを表示する最小サイズ

    • labelSize: ラベルのフォントサイズ

    • defaultNodeColor/defaultEdgeColor: デフォルトの色設定

インタラクティブ機能の実装

// ノードのクリックイベント
renderer.on('clickNode', (event) => {
    const node = event.node;
    graph.setNodeAttribute(node, 'color', getRandomColor());
    renderer.refresh();
});

// マウスホイールでのズーム
renderer.getMouseCaptor().on('wheel', (event) => {
    const factor = event.delta > 0 ? 1.1 : 0.9;
    camera.animatedZoom({ duration: 200, factor });
});
  • イベントリスナーの設定:

    • clickNode: ノードクリック時の色変更

    • wheel: マウスホイールでのズーム操作

  • getRandomColor(): ランダムな色を生成する関数

  • camera.animatedZoom(): アニメーション付きのズーム操作

実行

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

npm install

アプリケーション起動!

npm start

終わりに

リサーチ不足でSigma.jsで図形をグリグリできない事を知らずに試してしまったので、記事の趣旨と少し違うものになってしまいましたが、グラフネットワークとか作りたくなったらまたチャレンジしてみようと思います。

参考URL

Sigma.js

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

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

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