Vue CLI のプロジェクトで、nomnoml という JavaScript のライブラリを使用して、データベースのテーブルの ER ダイアグラムを作ってみたいと思います。
nomnoml は簡単な構文のマークダウンテキストを設定することで、UML ダイアグラム図を描画してくれる便利なツールです。
nomnoml は SVG 形式と Canvas 形式に対応しています。
今回は両方の形式で簡単な ER 図を描画してみます。
プロジェクトの準備
Vue CLI でプロジェクトを作成します。プロジェクト名は「nomnoml-project」とします。
ここではあらかじめ「npm uninstall -g vue-cli」コマンドが実行されており、Vue CLI がグローバルインストールされていることとします。
プロジェクトの作成
コマンドプロンプトでプロジェクトを作成するフォルダに移動して以下のコマンドを実行します。
1 |
vue create nomnoml-project |
実行するとプロジェクトの作成方法が表示されるので「Manually select features」を選択して進みます。
「Manually select features」を選択すると以下のようなプラグインの選択が表示されます。
ここでは TypeScript を追加でチェックして進みます。
プラグインの選択が終わると、プロジェクトについての選択がいくつか表示されます。基本は Enter でそのまま進みますが、リンターの選択では TSLint を選択して進みます。
プロジェクトについての選択が終わるとプロジェクトを保存するかどうかを問われるのでそのまま Enter (プロジェクトを保存しない) で進みます。
これでプロジェクトのテンプレートがインストールされます。
プロジェクトのインストールが終了したら、次に nomnoml をインストールします。
nomnoml のインストール
nomnoml をインストールします。
作成したプロジェクトのフォルダーに移動して、以下のコマンドを実行します。
1 |
install --save-dev nomnoml |
上記のコマンドを実行すれば nomnoml がインストールされるので、プロジェクトの準備は完了です。
コンポーネントの作成
プロジェクトの準備ができたので、ダイアグラムを描画するコンポーネントの作成に移ります。
ER 図を表示するコンポーネントは単一ファイルコンポーネントで作成してきます。
コンポーネントは nomnoml で UML ダイアグラムを描画する SVG を内部要素に持つ div 要素を配置したコンポーネントと、canvas 要素を配置したコンポーネントの2つを作成します。
nomnoml は、require で読み込みます。
1 |
const nomnoml = require('nomnoml'); |
SVG 形式のコンポーネントのソース
NomnomlSvg.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<template> <div> <!-- div 要素に v-html で SVG のデータを設定します。 --> <div v-html="svgData"></div> </div> </template> <script lang="ts"> import { Component, Prop, Watch, Vue } from 'vue-property-decorator'; // tslint:disable-next-line:no-var-requires const nomnoml = require('nomnoml'); @Component export default class Nomnoml extends Vue { // data に SVG を描画するための div 要素の HTML に設定するデータを作成します。 private svgData: string = ''; // props に nomnoml に設定するソースとなるテキストを作成します。 @Prop() private source!: string; // ER ダイアグラムを描画します。 private drawErDiagram(): void { if (!this.source) { this.clearErDiagram(); return; } try { // nomnoml の renderSvg 関数で SVG のデータを取得します。 this.svgData = nomnoml.renderSvg(this.source); } catch { this.clearErDiagram(); } } // ER ダイアグラムをクリアします。 private clearErDiagram(): void { this.svgData = ''; } // watch で props の source が変更されたときに ER ダイアグラムを描画するようにします。 @Watch('source') private onSourceChanged(newSource: string, oldSource: string) { this.drawErDiagram(); } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> </style> |
SVG 形式のコンポーネントでは nomnoml の renderSvg 関数にソースとなるテキストを渡して呼び出し、SVG のデータを取得して div 要素の inner HTML に設定しています。
Canvas 形式のコンポーネントのソース
NomnomlCanvas.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<template> <div> <!-- Vue の $refs で参照できるように canvas 要素に ref を指定します。 --> <canvas ref="canvas"></canvas> </div> </template> <script lang="ts"> import { Component, Prop, Watch, Vue } from 'vue-property-decorator'; // tslint:disable-next-line:no-var-requires const nomnoml = require('nomnoml'); @Component export default class Nomnoml extends Vue { // props に nomnoml に設定するソースとなるテキストを作成します。 @Prop() private source!: string; // ER ダイアグラムを描画します。 private drawErDiagram(): void { if (!this.source) { this.clearErDiagram(); return; } try { // Vue の $refs で canvas 要素を取得します。 const canvas = (this.$refs.canvas as HTMLCanvasElement); // nomnoml の draw 関数で Canvas に描画します。 nomnoml.draw(canvas, this.source); } catch { this.clearErDiagram(); } } // ER ダイアグラムをクリアします。 private clearErDiagram(): void { const canvas = (this.$refs.canvas as HTMLCanvasElement); canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); } // watch で props の source が変更されたときに ER ダイアグラムを描画するようにします。 @Watch('source') private onSourceChanged(newSource: string, oldSource: string) { this.drawErDiagram(); } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> </style> |
Canvas 形式のコンポーネントでは nomnoml の draw 関数に canvas 要素と、ソースとなるテキストを渡して呼び出して Canvas に描画しています。
コンポーネントを配置するアプリケーション
アプリケーションでは、nomnoml に設定するマークダウンテキストを入力できるテキストエリアと、SVG 形式と、Canvas 形式の両方のコンポーネントを配置します。
アプリケーションのソース
App.Vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<template> <div id="app"> <div class="columns frame"> <div class="column"> <!-- nomnoml に設定するソースを textarea 要素に v-model でバインドします。 --> <textarea class="textarea" v-model="source" /> </div> <div class="column"> <div class="label">SVG</div> <!-- SVG 形式のコンポーネント --> <nomnoml-svg v-bind:source="source"/> </div> <div class="column"> <div class="label">Canvas</div> <!-- Canvas 形式のコンポーネント --> <nomnoml-canvas v-bind:source="source"/> </div> </div> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; // コンポーネントを import します。 import NomnomlSvg from './components/NomnomlSvg.vue'; import NomnomlCanvas from './components/NomnomlCanvas.vue'; @Component({ components: { NomnomlSvg, NomnomlCanvas, }, }) export default class App extends Vue { // data に nomnoml に設定するソースとなるテキストを作成します。 private source: string = ''; } </script> <style lang="scss"> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; } .frame { margin: 10px } </style> |
上記のソースでは div 要素の class に columns 等を指定していますが、CSS フレームワークに Bulma を使用しています。
nomnoml に描画してみる
コンポーネントとアプリケーションの実装が完了したので、ブラウザに表示してみます。アドレスに http://localhost:8080 と入力してアクセスすると以下の画面が表示されます。
テキストエリアに nomnoml のサイトにあるサンプルのマークダウンテキストを張り付けてみます。
想定通りに UML ダイアグラム図が表示されました。
SVG 形式と Canvas 形式を比べるとサイズ (幅) が違います。SVG 形式の方が幅が広くなるようです。
ER 図を表示する
nomnoml で描画されることを確認できたので、いよいよデータベースのテーブルの ER 図を表示します。
まずは、ER 図を作成するためのテーブルを用意します。
ER 図を作成するテーブル
以下に ER 図を作成するために必要なテーブルの定義を記載します。ここでは 注文テーブル、注文アイテムテーブル、顧客マスタテーブル、商品マスタテーブル、カテゴリーマスタテーブルの5つのテーブルを用意しています。
Order (注文テーブル)
列 論理名 | 列 物理名 | データ型 |
---|---|---|
注文 ID | Id | int |
注文日 | OrderDate | varchar(8) |
顧客 ID | CustomerId | int |
OrderItem (注文アイテムテーブル)
列 論理名 | 列 物理名 | データ型 |
---|---|---|
注文 ID | OrderId | int |
アイテム番号 | ItemNo | int |
商品コード | ProductCode | varchar(5) |
数量 | Quantity | int |
Customer (顧客マスタテーブル)
列 論理名 | 列 物理名 | データ型 |
---|---|---|
顧客 ID | Id | int |
氏名 (姓) | LastName | varchar(50) |
氏名 (名) | FirstName | varchar(50) |
電話番号 | Tel | varchar(20) |
E メールアドレス | varchar(100) |
Product (商品マスタテーブル)
列 論理名 | 列 物理名 | データ型 |
---|---|---|
商品コード | Code | varchar(5) |
商品名 | Name | varchar(50) |
単価 | Price | decimal |
カテゴリーコード | CategoryCode | varchar(3) |
Category (カテゴリーマスタテーブル)
列 論理名 | 列 物理名 | データ型 |
---|---|---|
カテゴリーコード | Code | varchar(3) |
カテゴリー名 | Name | varchar(50) |
注文テーブルは顧客 ID で顧客マスタテーブルと紐づきます。
注文アイテムテーブルは注文 IDで注文テーブルと紐づき、商品コードで商品マスタテーブルと紐づきます。
商品マスタテーブルはカテゴリーコードでカテゴリーマスタテーブルと紐づきます。
上記のテーブルをもとに nomnoml で描画するためのテキストを作成すると以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
[Order| Id int OrderDate varchar(8) CustomerId int] [OrderItem| OrderId int ItemNo int ProductCode varchar(5) Quantity int] [Customer| Id int LastName varchar(50) FirstName varchar(50) Tel varchar(20) Email varchar(100)] [Product| Code varchar(5) Name varchar(50) Price decimal] [Category| Code varchar(3) Name varchar(50)] [Customer]<-[Order] [Order]<-[OrderItem] [Product]<-[OrderItem] [Category]<-[Product] #fill: #ddeeff; #ccddee #lineWidth: 2 #leading: 1.5 |
これをテキストエリアに入力して ER 図を表示します。
nomnoml は本来、テーブルの ER 図を作成するツールではありませんが、それらしく ER 図を表示することができました。
今回は nomnoml の基本的な機能のみ使用しましたが、nomnoml では描画をカスタマイズするための様々なディレクティブや、関連付けのタイプ、分類子のタイプなどが用意されています。
UML ダイアグラム図を Web サイト等に表示する必要があれば、皆さんも nomnoml を使ってみてください。