上級者向け: TL の追加ヒント

東西隣接ノードの指定

2 つの無関係のノードを、方向選択に対して垂直な方向に直接隣接するように指定できます。 レベル・レイアウト・モードおよび放射レイアウト・モードでは、ノードは同じレベルで隣り合わせに配置されます。 自由レイアウト・モードおよび傾斜モードでは、ノードは北ボーダーに整列して配置されます。 これらのノードは、片方のノードがもう片方のノードの東側に直接の隣接ノードとして配置されるため、東西隣接ノード と呼ばれます。 もう片方のノードは、最初のノードの西側の直接隣接ノードになります。 (位置レイアウト・パラメーターのコンパス方向の使用 (TL) も参照してください。)
厳密には、2 つのノードは、互いを結ぶリンクがなくても親と子として扱われます。そのため、2 つのノードの一方は実際の親を持つことができますが、 もう片方は、仮想の親が東西隣接ノード であるため、親を持つことができません。
例えば、コンパイラー構成で発生するタイプ付き構文ツリーでノードにアノテーションを付けるために、東西隣接ノード・フィーチャーを使用できます。 ステートメント a[25] = b[24] + 0.5 の、アノテーションが付けられた構文ツリー に、このようなツリーの例を示します。

東西隣接パラメーターを使用した例を示すツリー・レイアウトの図
ステートメント a[25] = b[24] + 0.5 の、アノテーションが付けられた構文ツリー
2 つのノードが東西隣接ノードであることを指定するには、以下のメソッドを使用します。
treeLayout.setEastWestNeighboring(eastNode, westNode);
また、以下の関数を使用することもできます。この関数は、パラメーターの順序が逆である点を除いて同じです。
treeLayout.setWestEastNeighboring(westNode, eastNode);
方向選択が下向きの場合は、レイアウトで西が東の左になり、パラメーターのテキストの向きと同様になるため、後者のメソッドの方が覚えやすいかもしれません。
ノードの東または西の隣接ノードを取得するには、以下の呼び出しを使用します。
var eastNode = treeLayout.getEastNeighbor(westNode);
var westNode = treeLayout.getWestNeighbor(eastNode);
各ノードに設定できる東隣接ノードおよび西隣接ノードは、直接 隣接ノードであるため、最大でそれぞれ 1 つずつです。複数の直接隣接ノードが指定された場合、部分的に無視されます。 循環的に指定した場合も、競合が生じる可能性があります。 例えば、ノード B がノード A の東隣接ノードであり、ノード C が B の東隣接ノードである場合、 ノード A は C の東隣接ノードにすることはできません。 (厳密に言えば、放射レイアウト・モードの一部の場合に、このような循環が理論的には可能になることもありますが、どのレイアウト・モードでも循環は許可されていません)。
B が A の東隣接ノードの場合、A は自動的に B の西隣接ノードになります。 A の東隣接ノード自体には、別の東隣接ノードを設定できます。 これにより、東西隣接ノードのチェーンを作成できます。 これはツリーのリストを視覚化するためによく使用される手法です。 図 ツリーのリストを視覚化するための東西隣接ノードのチェーン に 2 つの例を示します。

東西隣接ノードのチェーンを使用した例を示すツリー・レイアウトの図
ツリーのリストを視覚化するための東西隣接ノードのチェーン

リンク・カテゴリーの取得

TL アルゴリズム の記載のとおり、 ツリー・レイアウト・アルゴリズムはスパンニング・ツリーで機能します。 レイアウトするグラフがピュア・ツリーでない場合は、アルゴリズムは一部のリンクを無視します。 そのようなリンクを特別な方法で処理するために、非ツリーのリンクのリストを取得できます。
スパンニング・ツリーには親ノードと子ノードがあるため、以下のリンク・カテゴリーを区別する必要があります。
  • フォワード・ツリー・リンクは、親から子へのリンクです。
  • バックワード・ツリー・リンクは、子から親へのリンクです。 リンクが有向矢印として描画されている場合、その矢印は、方向選択の逆方向に向かいます。
  • 非ツリー・リンクは、2 つの無関係のノード間のリンクです。どちらのノードも相手ノードの子ではありません。

さまざまなリンク・カテゴリーを示す図
リンク・カテゴリー
レイアウト・アルゴリズムはこれらのリンク・カテゴリーを内部で使用しますが、時間を節約し、メモリー効率を確保するために、それらを永久に保存することはしません。 一部のリンク・カテゴリーを特殊に扱う (例えば、非ツリー・リンクでリンク・レイアウトを呼び出す) 場合は、 レイアウト後に リンク・カテゴリーにアクセスすることを、レイアウト前に 指定する必要があります。
これを行うには、メソッド setCategorizingLinks を以下のように使用します。
  treeLayout.setCategorizingLinks(true);
  graph.setNodeLayout(treeLayout);
  graph.performGraphLayout();
  var link;
  var forwardLinks = treeLayout.getCalcForwardTreeLinks();
  console.log("forward links:");
  while(forwardLinks.hasNext()){
   link = forwardLinks.next();
   console.log(link.getStartNode().getLabel() + " -> " + link.getEndNode().getLabel());
  }
  var backwardLinks = treeLayout.getCalcBackwardTreeLinks();
  console.log("backward links:");
  while(backwardLinks.hasNext()){
   link = backwardLinks.next();
   console.log(link.getStartNode().getLabel() + " -> " + link.getEndNode().getLabel());
  }
  var nonTreeLinks = treeLayout.getCalcNonTreeLinks();
  console.log("non-tree links:");
  while(nonTreeLinks.hasNext()){
   link = nonTreeLinks.next();
   console.log(link.getStartNode().getLabel() + " -> " + link.getEndNode().getLabel());
  }
レイアウトの実行後に、リンク・カテゴリーにアクセスできます。
メソッド setCategorizingLinks(false) を呼び出さない限り、レイアウトを呼び出すごとにリンク・カテゴリー・データが埋められます。

インクリメンタルな変更を使用したレイアウトのシーケンス

古くなったツリー (例えば、子ノードを増やして拡張する必要があるツリーなど) を処理できます。 拡張後にレイアウトを実行した場合、元のグラフで既にレイアウトされていた部分を識別する必要が恐らく生じます。 ツリー・レイアウト・アルゴリズムは、ノードの以前の位置を考慮に入れるため、インクリメンタル・モードでのこのようなインクリメンタルな変更をサポートします。 後続のレイアウトで、子ノードの相対順序が保持されます。
非インクリメンタル・モードでは、ツリー・レイアウト・アルゴリズムは、 接続されたグラフ・モデル (グラフ) によって提供されたノード順序から子ノードの順序を計算します。
この場合、レイアウトは、レイアウト前のノードの位置から独立しています。後続のレイアウトで、子ノードの相対順序は保持されません。
デフォルトでは、インクリメンタル・モードは使用可能です。
インクリメンタル・モードを使用不可にするには、以下のようにします。
以下を呼び出します。
treeLayout.setIncrementalMode(false);

対話式編集

レイアウトの相対順序が保持されるということは、対話式編集時には有用です。これにより、レイアウトを簡単に修正できます。 例えば、最初のレイアウトがノード A を兄弟ノード B の左に配置したが、 順序を逆にする必要が生じた場合、単にノード A をノード B の右に移動して新規レイアウトを開始し、描画をクリーンアップできます。 2 番目のレイアウトで、A は B の右にとどまり、A のサブツリーはノード A に「従い」ます。
ノードを移動してからレイアウトを再実行した場合の効果を示す、3 つのピクチャー
子ノードの特定の順序を実現するための対話式編集

子ノードの順序の指定

一部のアプリケーションでは、ツリー内の子ノードの特定の相対順序が必要になります。 例えば、方向選択が下向きの場合にどの子を別の子の左に配置する必要があるのか、などです。
これは、以下のように、ノード・コンパレーターを指定することで、非インクリメンタル・モードで実現できます。
  treeLayout.setNodeComparator(function(node1, node2) {
   // for example: sort nodes by increasing width
   return node1.getBounds().width - node2.getBounds().width;
  });
コンパレーターは、以下の表に定義されているように順序を指定します。 通常の整列の場合、子の座標が増大します。 傾斜整列の場合、親からの距離が大きくなります。バルーン・モードおよび放射モードの場合、右回りの順序付けになります。
レイアウト・モード 整列 方向選択 順序
自由、レベル、傾斜 非傾斜 左から右へ
左から右へ
上から下
上から下
自由、レベル、傾斜 傾斜 上から下
下から上
右から左
左から右へ
放射、バルーン 任意 任意 右回り