ノードの視覚属性の設定は文字列の表示と同じような方法で行います。BasicVisualizationServer[MyNode,MyEdge]型のpanelに対して、各ノードと視覚属性を対応付ける写像を設定します。写像はTransformer型のオブジェクトのtransform()メソッドによって定義します。
ノードから塗り色への写像はTransformer[MyNode,Paint]のオブジェクトで定義し、その写像をsetVertexFillPaintTransformer()メソッドで設定します。
1: import swing._ 2: import java.util._ 3: import java.awt.{Color,Dimension,Paint} 4: import java.awt.geom.Point2D 5: import org.apache.commons.collections15.Transformer 6: import edu.uci.ics.jung.algorithms.layout.{Layout,StaticLayout} 7: import edu.uci.ics.jung.graph.{Graph,UndirectedSparseGraph} 8: import edu.uci.ics.jung.visualization.BasicVisualizationServer 9: object Sample5a extends SimpleSwingApplication { 10: def top = new MainFrame { 11: title = "Graph View: Blue Nodes" 12: val (graph, layout) = createGraph 13: val panel = new BasicVisualizationServer[MyNode,MyEdge](layout, new Dimension(300, 300)) 14: val nodeFillColor = new Transformer[MyNode,Paint] { 15: override def transform(n: MyNode): Paint = Color.BLUE 16: } 17: panel.getRenderContext.setVertexFillPaintTransformer(nodeFillColor) 18: contents = Component.wrap(panel) 19: } 20: def createGraph: Tuple2[Graph[MyNode,MyEdge],Layout[MyNode,MyEdge]] = { 21: val graph: Graph[MyNode,MyEdge] = new UndirectedSparseGraph[MyNode,MyEdge]() 22: val n1 = new MyNode("n1") 23: val n2 = new MyNode("n2") 24: val n3 = new MyNode("n3") 25: graph.addVertex(n1) 26: graph.addVertex(n2) 27: graph.addVertex(n3) 28: graph.addEdge(new MyEdge("e1"), n1, n2) 29: graph.addEdge(new MyEdge("e2"), n2, n3) 30: val layout: Layout[MyNode,MyEdge] = new StaticLayout[MyNode,MyEdge](graph) 31: layout.setLocation(n1, new Point2D.Double(100, 100)) 32: layout.setLocation(n2, new Point2D.Double(200, 100)) 33: layout.setLocation(n3, new Point2D.Double(150, 200)) 34: (graph, layout) 35: } 36: }
ノードから色への写像は、14行目から16行目で、Transformer[MyNode,Paint]型のオブジェクトのtransform()メソッドによって定義しています。ここでは15行目で、Color.BLUE(青色)を指定しています。定義した写像nodeFillColorを、17行目で、BasicVisualizationServer[MyNode,MyEdge]型のpanelに対して、setVertexFillPaintTransformer()メソッドで設定しています。
上のプログラムを実行するとするとノードが下のように描かれます。
Transformer[MyNode,Paint]型のオブジェクトのtransform()メソッドはMyNodeを引数として取るので、ノード毎に色を変えることもできます。
14: val nodeFillColor = new Transformer[MyNode,Paint] { 15: override def transform(n: MyNode): Paint = { 16: val id: Int = n.label.substring(1).toInt 17: new Color(Color.HSBtoRGB(id / 3f, 0.7f, 1.0f)) 18: } 19: }
16行目でノードに指定された文字列から整数(「n1」の場合には1)を取り出しています。17行目では、取り出した整数を(ここではノード数が3なので)3で割ってHue(色相)のパラメータとし、色空間HSBからRGBに変更して、ノードnの色としています。16行目と17行目は、若干面倒なことをしていますが、その方法自体は重要ではありません(分らなければ無理して理解する必要はありません)。重要なことはノードnに対して適当なColor型のオブジェクトを返すようにtransform()メソッドを適切に定義することです。
上のように改造したプログラムを実行するとするとノードが下のように描かれます。
ノード内部を塗り潰す色だけでなく、輪郭線の色を指定することもできます。輪郭線の色はsetVertexDrawPaintTransformer()メソッドで設定します。次の例では境界線を緑にしています。
14: val nodeDrawColor = new Transformer[MyNode,Paint] { 15: override def transform(n: MyNode): Paint = Color.GREEN 16: } 17: panel.getRenderContext.setVertexDrawPaintTransformer(nodeDrawColor)
Transformer[MyNode,Paint]型のオブジェクトの定義は塗り潰し色の指定と同様です。ここではtransform()メソッドは単にColor.GREENを返しています。こうして定義したnodeDrawColorをsetVertexDrawPaintTransformer()メソッドで指定します。
上のように改造したプログラムを実行するとすると下のようにノードが描かれます。画面では分り難いかも知れませんが、ノードの輪郭線が緑色で描かれています。
少し違う方法を使うと、ノードの塗り色にグラデーションを指定することもできます。
14: panel.getRenderer.setVertexRenderer( new GradientVertexRenderer[MyNode,MyEdge]( Color.YELLOW, Color.BLUE, false))
上のように設定すると下のようなノードが描かれます。
形状の設定も色と同様の方法で行います。ノードから形状への写像をTransformer[MyNode,Shape]型のオブジェクトで定義し、その写像をsetVertexShapeTransformer()メソッドで設定します。
14: val nodeShapeTransformer = new Transformer[MyNode,Shape] { 15: override def transform(n: MyNode): Shape = new Rectangle(-15, -10, 30, 20) 16: }; 17: panel.getRenderContext.setVertexShapeTransformer(nodeShapeTransformer)
ノードの形状の定義は、14行目から16行目で、Transformer[MyNode,Shape]型のオブジェクトのtransform()メソッドによって定義しています。エッジは原点をつなぐように描かれるので、原点が中心になるようにノードの座標を指定すると良いでしょう。ここでは、(-15, -10)を左上の点とする横30、縦20の長方形(Rectangle)を指定しています。17行目でノードの形状の定義nodeShapeTransformerを指定しています。
上のプログラムを実行するとすると下のようなウィンドウが現われます。
エッジの色の設定もノードと同様の方法で行います。エッジから色への写像はTransformer[MyEdge,Color]型のオブジェクトで定義し、その写像をsetEdgeDrawPaintTransformer()メソッドで設定します。
14: val edgeColor = new Transformer[MyEdge,Paint] { 15: override def transform(e: MyEdge): Paint = Color.BLUE 16: } 17: panel.getRenderContext.setEdgeDrawPaintTransformer(edgeColor)
上のように設定すると下のようにエッジが描かれます。
エッジの形状の設定はsetEdgeShapeTransformer()メソッドで行います。たとえば、エッジを直線分(Line)で表すには下のようにします。
14: panel.getRenderContext.setEdgeShapeTransformer(new EdgeShape.Line[MyNode,MyEdge])
上のように設定すると下のようにエッジが描かれます。
直線分以外にも、以下のような形状が用意されています。
エッジの太さの設定は、エッジに対してStrokeオブジェクトを指定することで行います。エッジからStrokeへの写像はTransformer[MyEdge,Stroke]型のオブジェクトで定義し、その写像をsetEdgeStrokeTransformer()メソッドで設定します。
14: val edgeStroke: Stroke = new BasicStroke(10.0f) 15: val edgeStrokeTransformer = new Transformer[MyEdge,Stroke] { 16: override def transform(e: MyEdge): Stroke = edgeStroke 17: } 18: panel.getRenderContext.setEdgeStrokeTransformer(edgeStrokeTransformer)
上のように設定すると下のようにエッジが描かれます。
エッジに対応するStrokeを変更することで、太さだけでなく線種も設定できます。
14: val dash = Array(5f) 15: val edgeStroke: Stroke = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f) 16: val edgeStrokeTransformer = new Transformer[MyEdge,Stroke] { 17: override def transform(e: MyEdge): Stroke = edgeStroke 18: } 19: panel.getRenderContext.setEdgeStrokeTransformer(edgeStrokeTransformer)
上のように設定すると下のようにエッジが描かれます。
配列dashの値によって破線のパターンを変更できます。たとえばdash = Array(10f, 3f, 3f, 3f)とすると一点鎖線を描くことができます。その他、下のようなパターンも試してみて下さい。