GoJSをはじめよう

GoJS は、インタラクティブダイアグラムを実装するためのJavaScriptライブラリです。

GoJSはHTML5機能に依存したJavaScriptライブラリであるため、ページでは「HTML5文書宣言」する必要があります。通常、HTMLヘッダで、ライブラリをロードします。


<!DOCTYPE html>  <!-- HTML5 document type -->
<html>
<head>
  <script src="go-debug.js"></script>  <!-- use go.js when deploying -->
  . . .
    

GoJS で作成した図は、明示的にサイズを指定した HTMLページのdiv 要素に含まれます。


<!-- The DIV for a Diagram needs an explicit size or else we will not see anything.
     In this case we also add a background color so we can see that area. -->
<div id="myDiagramDiv"
     style="width:400px; height:150px; background-color: #DAE4E4;"></div>
    

JavaScriptコードでは、ダイアグラムを作成する際、dividを渡します。


var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv");
    

空のダイアグラムを作成

go は "名前空間" です。 "Diagram" 、 "Node" 、 "Panel" 、 "Shape" 、 "TextBlock" など、GoJS の全てのクラスは、 接頭辞"go."を付けます。

ここでは、 GoJSオブジェクトを構築するため go.GraphObject.make をどのように使用するか、について紹介します。 詳細は、Building Objects in GoJSを読んでください。 go.GraphObject.makeの略語として $ を使用すると便利です。 あるいは、$$ or MAKE or GOのように短い変数名を選択することが出来ます。

ダイアグラムとモデル

図の内容は、モデルによって管理されます。 GoJS は、model-viewアーキテクチャの仕組みを持っています。 モデルは、ノードとリンクを記述したデータ(JavaScriptのオブジェクトの配列)を保持しています。 ビューとして機能するダイアグラムは、実ノードとリンクオブジェクトを使用してこのデータを可視化します。

モデルとダイアグラムの例


var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center, // センターダイアグラムの内容
      "undoManager.isEnabled": true // Ctrl-Zで元に戻す、Ctrl-Yでやり直す、機能を有効にする
    });

var myModel = $(go.Model);
// GoJSのモデルデータでは、各ノードは、JavaScriptオブジェクトで表される
myModel.nodeDataArray = [
  { key: "Alpha" },
  { key: "Beta" },
  { key: "Gamma" }
];

myDiagram.model = myModel;
    

モデルである3つの図が表示されます。幾つかの相互作用機能は動作可能です。

ノードのスタイリング

ノードは、テンプレートを作成し、データバインディングを経由してテンプレート内でデータバインディングしたモデルデータプロパティを関連付けることにより、スタイリングされています。 ノードを作成するために、予め幾つかの building ブロッククラスが用意されています。

これらの構成要素のすべてが GraphObject クラスから派生しているので、GraphObjectsまたはオブジェクトまたは要素としてそれらを参照してください。

データバインディングにより、モデルデータはノードに影響を与えます。GraphObjectsのプロパティを自動設定することにより、ノードの外観と動作を変更することができます。

デフォルトのノードテンプレートはシンプルです。1つの TextBlockを含みます。TextBlockのtext プロパティとモデルデータのkeyプロパティはデータバインディングされています。


myDiagram.nodeTemplate =
  $(go.Node,
    $(go.TextBlock,
      // TextBlock.text は、Node.data.key にバインドされている
      new go.Binding("text", "key"))
  );
    

より一般的には、ノードテンプレートの骨格は次のようになります。


myDiagram.nodeTemplate =
  $(go.Node, "Vertical" // ノード/パネルの第2引数は、パネルタイプを指定することが可能
    { /* ここでは、ノードのプロパティを設定 */ },
    new go.Binding("location", "loc"),  // ノードバインディングの例
    // ノード内に含まれているGraphObjects 
    $(go.Shape, "RoundedRectangle" // 文字列引数は、事前定義された図に名前を付けることが可能
      { /* ここで図形のプロパティを設定 */ },
      new go.Binding("figure", "fig")), // バインディングする図形の指定例
    $(go.TextBlock, "default text",  // 文字列引数は、最初のテキスト文字列を使用できる
      { /* ここでTextBlockのプロパティを設定 */ },
      new go.Binding("text", "key")) // TextBlockバインディング例
  );
    

ネストは任意の深さに設定可能で、すべてのクラスは独自のプロパティを持っています。

これまでノードテンプレートを作成する方法を見てきましたので、次に実際の例を見てみましょう。 名前の横に画像があるような、組織図に見られる単純なテンプレートを作成します。


var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center, // センターダイアグラムの内容
      "undoManager.isEnabled": true // 元に戻すにはCtrl-Z、やり直すにはCtrlキーを押しながらY、を有効にする
    });

// 簡単なノードテンプレートを定義する
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    // ノード全体が水色の背景を持つ
    { background: "#44CCFF" },
    $(go.Picture,
      //画像には、幅と高さを明示的に指定する必要がある 
      //この画像は、ソースセットが存在しないときや、
      //イメージが部分的に透明であるときにのみ、赤い背景を表示する
      { margin: 10, width: 50, height: 50, background: "red" },
      // Picture.source は、モデルデータの"source"属性にデータバインドされている
      new go.Binding("source")),
    $(go.TextBlock,
      "Default Text",  // TextBlock.textの初期値
      // テキストの周りに含みを残しておく、大きいフォント、白のストローク
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
       // TextBlock.textは、モデルデータの「name」属性にデータバインドされている
      new go.Binding("text", "name"))
  );

var model = $(go.Model);
model.nodeDataArray =
[
  { name: "惑星ベジータ生まれの戦闘民族サイヤ人",  source: "cat1.png" },
  { name: "カカロット", source: "cat2.png" },
  { name: "ベジータ", source: "cat3.png" },
  { /* 空のノードデータ */  }
];
myDiagram.model = model;
    

上記コードは、この図を生成します。

モデルの種類

「個別のノード」と「自動的にノードを配置するレイアウト」との関係を示すために、いくつかのリンクを追加することで、完全な組織図·ダイアグラムを作成します。

GraphLinksModel and TreeModel

GraphLinksModelでは、model.nodeDataArrayに加えて model.linkDataArray を持っている。 node keysを"from""to"と指定しリンクを記述すると、JavaScriptのオブジェクト配列を保持します。 ノードAをBへ、ノードBをCへリンクする例を示します。


var model = $(go.GraphLinksModel);
model.nodeDataArray =
[
  { key: "A" },
  { key: "B" },
  { key: "C" }
];
model.linkDataArray =
[
  { from: "A", to: "B" },
  { from: "B", to: "C" }
];

myDiagram.model = model;
    

TreeModelで上記と同じ内容のグラフを描画


var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "A" },
  { key: "B", parent: "A" },
  { key: "C", parent: "B" }
];

myDiagram.model = model;
    

TreeModelはGraphLinksModelよりも簡単ですが、同じ2つのノード間で、複数リンクや複数の親を持つような、任意のリンク関係を作ることができません。 現在作成している組織図は、単純な階層ツリー状の構造なので、今後もTreeModelを使用していきます。

まず私たちは、TreeModelを使用してさらにいくつかのノードを追加し、データ内のキーと親を指定して、データを終了します。


var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center, // センターダイアグラムの内容
      "undoManager.isEnabled": true // 元に戻すにはCtrl-Z、やり直すにはCtrlキーを押しながらY、を有効にする
    });

// 先ほど定義したテンプレート
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    { background: "#44CCFF" },
    $(go.Picture,
      { margin: 10, width: 50, height: 50, background: "red" },
      new go.Binding("source")),
    $(go.TextBlock, "Default Text",
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      new go.Binding("text", "name"))
  );

var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "1",              name: "惑星ベジータ生まれの戦闘民族サイヤ人",   source: "cat1.png" },
  { key: "2", parent: "1", name: "ベジータ",    source: "cat2.png" },
  { key: "3", parent: "1", name: "カカロット",   source: "cat3.png" },
  { key: "4", parent: "3", name: "孫悟飯", source: "cat4.png" },
  { key: "5", parent: "3", name: "孫悟天",     source: "cat5.png" },
  { key: "6", parent: "2", name: "トランクス", source: "cat6.png" }

];

myDiagram.model = model;
    

ダイアグラムのレイアウト

TreeModelはノードを関連付けるために必要なリンクを自動的に作成しますが、親が誰であるかを伝えるのは難しいです。

ダイアグラムは、「locationを持っていないすべてのノードを取得しlocationを与えた上でグリッドに配置する」デフォルトのレイアウトを持っている。組織図の場合は、各ノードへ個別にlocation設定するのではなく、自動的に最適なlocationを設定する方式を採用している。

階層を表示するために最も自然なレイアウト選択は、既にTreeModelを使用しているツリーレイアウトです。ツリーレイアウトのデフォルトは、左から右へ流れるため、(組織図に一般的であるように)上から下へ流れるようにするためには、角度プロパティを90へ設定します。

GoJSでは簡単にレイアウトを使用することが出来ます。レイアウトの種類ごとに、結果に影響を与えるプロパティがいくつかあります。そのプロパティのショーケースとなる(TreeLayoutデモのような)各レイアウトのサンプルがあります。


// 上から下へTreeLayoutを定義
myDiagram.layout =
  $(go.TreeLayout,
    { angle: 90, layerSpacing: 35 });
    

GoJSは、いくつかの他のレイアウトを持っています。 ここで読むことができます。

「これまでの図」と「モデルへのレイアウトの追加」結果を見ることができます:


var $ = go.GraphObject.make;
var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center, // センターダイアグラムの内容
      "undoManager.isEnabled": true // 元に戻すにはCtrl-Z、やり直すにはCtrlキーを押しながらY、を有効にする
    });

// 先ほど定義したテンプレート
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    { background: "#44CCFF" },
    $(go.Picture,
      { margin: 10, width: 50, height: 50, background: "red" },
      new go.Binding("source")),
    $(go.TextBlock, "Default Text",
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      new go.Binding("text", "name"))
  );

myDiagram.layout =
  $(go.TreeLayout,
    { angle: 90, layerSpacing: 35 });

var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "1",              name: "惑星ベジータ生まれの戦闘民族サイヤ人",   source: "cat1.png" },
  { key: "2", parent: "1", name: "ベジータ",    source: "cat2.png" },
  { key: "3", parent: "1", name: "カカロット",   source: "cat3.png" },
  { key: "4", parent: "3", name: "孫悟飯", source: "cat4.png" },
  { key: "5", parent: "3", name: "孫悟天",     source: "cat5.png" },
  { key: "6", parent: "2", name: "トランクス", source: "cat6.png" }

];
myDiagram.model = model;
    

私たちの図は、組織図のようになり始めているが、リンクを伴うことでよりよくすることができます。

リンクテンプレート

箱型のノードに合う新しいリンクテンプレートを構築します。 リンク はノードのような形状ではなく、 メイン要素として、GoJSが動的に位置計算しているリンク形状を含みます。通常の黒のダークグレーより少し厚めのストローク。デフォルトのリンクテンプレートとは異なり、矢じりを持っていません。そして、通常の直交リンクルーティングプロパティを変更し、直角ターンが丸みを帯びているように表示します。


// リンクテンプレートのルートを直角かつ矢印なしで定義
myDiagram.linkTemplate =
  $(go.Link,
    // Default routing is go.Link.Normal
    // Default corner is 0
    { routing: go.Link.Orthogonal, corner: 5 },
    $(go.Shape, { strokeWidth: 3, stroke: "#555" }) // the link shape

    // 矢印の場合は、定義されたtoArrowとは別の図形を追加 
    // $(go.Shape, { toArrow: "Standard", stroke: null }
    );
    

ノードテンプレートを伴うリンクテンプレート、TreeModel、TreeLayoutを組み合わせることで、完全な組織図を作成することができます。コードとその結果は次のとおりです。


var $ = go.GraphObject.make;

var myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center, // センターダイアグラムの内容
      "undoManager.isEnabled": true // 元に戻すにはCtrl-Z、やり直すにはCtrlキーを押しながらY、を有効にする
    });

// 先ほど定義したテンプレート
myDiagram.nodeTemplate =
  $(go.Node, "Horizontal",
    { background: "#44CCFF" },
    $(go.Picture,
      { margin: 10, width: 50, height: 50, background: "red" },
      new go.Binding("source")),
    $(go.TextBlock, "Default Text",
      { margin: 12, stroke: "white", font: "bold 16px sans-serif" },
      new go.Binding("text", "name"))
  );

// Define a Link template that routes orthogonally, with no arrowhead
myDiagram.linkTemplate =
  $(go.Link,
    { routing: go.Link.Orthogonal, corner: 5 },
    $(go.Shape, { strokeWidth: 3, stroke: "#555" })); // the link shape

myDiagram.layout =
  $(go.TreeLayout,
    { angle: 90, layerSpacing: 35 });

var model = $(go.TreeModel);
model.nodeDataArray =
[
  { key: "1",              name: "惑星ベジータ生まれの戦闘民族サイヤ人",   source: "cat1.png" },
  { key: "2", parent: "1", name: "ベジータ",    source: "cat2.png" },
  { key: "3", parent: "1", name: "カカロット",   source: "cat3.png" },
  { key: "4", parent: "3", name: "孫悟飯", source: "cat4.png" },
  { key: "5", parent: "3", name: "孫悟天",     source: "cat5.png" },
  { key: "6", parent: "2", name: "トランクス", source: "cat6.png" }

];
myDiagram.model = model;
    

GoJSで可能なダイアグラムのいくつかを見るためにサンプル熟読検討し、 GoJSのコンポーネント詳細を理解するために 技術紹介をお読みください。