2021-02-27

Diagram Maker動かしてみた

DiagramMakerを動かしてみたので備忘録。
すぐ動くサンプル無さそうだったので…

サンプルはここに置いてます https://github.com/tzmfreedom/javascript-sample/tree/master/diagram-maker-sample

インストール

$ npm install diagram-maker

TypeScriptじゃなくても動くようですが公式のサンプルがTypeScriptだったり、ちゃんとstyleあてないといけないといけなかったりするので webpackや各種loaderも併せて一式インストール

$ npm install @types/node \
    style-loader \
    css-loader \
    sass \
    sass-loader \
    typescript \
    ts-loader \
    dagre \
    redux \
    webpack \
    webpack-cli

ざっと使い方

セレクタを指定して要素に対してDiagramMakerをアタッチするような使い方になるので、HTMLにそれ用の要素を用意します。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>DiagramMaker Test Environment</title>
    </head>
    <body>
        <div id="diagramMakerContainer"></div>
        <div id="diagramMakerLogger"></div>
        <script src="./bundle.js"></script>
    </body>
</html>

JSはこんな感じで書く。第一引数はマウントするセレクタ。

import { DiagramMaker } from 'diagram-maker';

const config = {
  // ...
};
const initData = {
  // ...
};
const diagramMaker = new DiagramMaker(
  'diagramMakerContainer',
  config,
  // optionParams
  {
    initialData: initData
  }
);

configの例

const config = {
  options: {
    // コネクタの場所を定義
    // ノードごとにコネクタの位置を定義したい場合はnodeTypeConfigのconnectorPlacementOverrideプロパティで上書き可能
    connectorPlacement: ConnectorPlacement.LEFT_RIGHT
  },
  // DOM操作してノードの見た目を定義したり、クリック時の処理を変更するメイン設定
  renderCallbacks: {
    destroy: () => undefined,
    node: (node: DiagramMakerNode<{}>, container: HTMLElement) => {
      // workspaceに置かれるノードのDOMを作成する関数
      // HTMLElementなcontainerに対してinnerHTMLやappendChildを使ってHTMLを定義
      // nodeのデータにはnodeの種別やユーザ定義データが含まれるので、それを使って表示する内容を変更することが可能
      return createRectangularNode(node, container);
    },
    potentialNode: (node: DiagramMakerPotentialNode, container: HTMLElement) => {
      // 新規作成用のノードをドラッグしているときに表示されるノードのHTMLを定義
      return createPotentialNode(node, container);
    },
    panels: {
      // パネルを定義するところで、パネルに新規作成用のノードを置いたり、操作メニュー的な使い方が可能。
      // library: (panel: any, state: any, container: HTMLElement) => createLibraryPanel(container),
      // tools: (
      //       panel: any,
      //       state: any,
      //       container: HTMLElement
      // ) => createToolsPanel(container, () => windowAsAny.diagramMaker)
    },
    contextMenu: {
      // node, edge, panel, workspaceに対する右クリック時のコンテキストメニューの処理を定義
      node: (id: string | undefined, container: HTMLElement) => createNodeContextMenu(id, container),
      edge: (id: string | undefined, container: HTMLElement) => createEdgeContextMenu(id, container),
      panel: (id: string | undefined, container: HTMLElement) => createPanelContextMenu(id, container),
      workspace: (container: HTMLElement) => createWorkspaceContextMenu(container)
    } as ContextMenuRenderCallbacks
  },
  actionInterceptor: (action: Action, next: Dispatch<Action>, getState: () => DiagramMakerData<{}, {}>) => {
    // 各操作に対して処理を挟み込める
    next(action);
  },
  // ノードの種別やサイズを定義
  nodeTypeConfig: {
    'testId-centered': {
      size: { width: 100, height: 100 },
      connectorPlacementOverride: ConnectorPlacement.CENTERED
    },
    // ...
  }
};

データの例

export const graph: DiagramMakerData<{}, {}> = {
  nodes: {
    // ノードの定義
    node1: {
      id: 'node1',
      diagramMakerData: {
        position: { x: 200, y: 150 },
        size: { width: 100, height: 50 }
      },
      // ユーザ定義データはconsumerDataに入れる
      consumerData: {}
    },
    node2: {
      id: 'node2',
      diagramMakerData: {
        position: { x: 400, y: 300 },
        size: { width: 100, height: 50 }
      },
      consumerData: {}
    }
  },
  edges: {
    edge1: {
      id: 'edge1',
      src: 'node1',
      dest: 'node2',
      diagramMakerData: { }
    }
  },
  panels: {
    // パネルの座標や大きさの定義。パネルの中の要素やノードはconfigで設定する
    [`library`]: {
      id: `library`,
      position: { x: 20, y: 20 },
      size: { width: 250, height: 600 },
      positionAnchor: PositionAnchor.TOP_RIGHT
    },
    [`tools`]: {
      id: `tools`,
      position: { x: 20, y: 20 },
      size: { width: 150, height: 400 }
    }
  },
  workspace: {
    position: { x: 0, y: 0 },
    scale: 1,
    canvasSize: { width: 3200, height: 1600 },
    viewContainerSize: { width: window.innerWidth, height: window.innerHeight }
  },
  editor: { mode: EditorMode.DRAG }
};

また、APIを使ってstateを抽出したりレイアウトを変えたりできる

const currentState = diagramMaker.store.getState();
diagramMaker.store.subscribe(() => {
  console.log(diagramMaker.store.getState());
});

詳細は公式リファレンスを参照: https://awslabs.github.io/diagram-maker/usage/api.html

css/scssも当てないと何も表示されなかったりするので注意

import 'diagram-maker/dist/diagramMaker.css';
import '../scss/index.scss';
import '../scss/CircularNode.scss';
import '../scss/Logger.scss';
import '../scss/RectangularNode.scss';
このエントリーをはてなブックマークに追加