Thursday, August 13, 2009

Creating decorators in the Prefuse framework


I'm working on some graph visualization using Prefuse, and I want to allow the use to select nodes in the graph by dragging a marquee. In addition, I want to show a tiny black square indicator at the top-left corner of a selected node. The image on the left is what I eventually got.

I wanted to use the Decorator design pattern provided by Prefuse to add the square indicators. Conceptually, the steps are:
  1. programatically selects a subset of the nodes in the graph
  2. applies the desired decoration on those subset of nodes
But in the actual implementation, these basic steps unfold into much more complex steps:
  1. creates a "focus group", of type "DefaultTupleSet", to the "visualization" object, using the method visualization.addFocusGroup(); you'll need to give this newly created group a name. This group (which is a "tuple set") is precisely the data structure that you use to store the selected nodes
  2. look at this example on how to create a control that lets you draw the rectangle marquee, which will put the selected nodes into the "focus group" that you created in step 1.
  3. now comes the nontrivial part -- creating the "decorators", which are objects created to decorate the selected nodes. Programmatically, you call visualization.addDecorators() to create this new group of decorators. Again, you give this decorator group a name.
  4. creates a layout action to continously relocate the indicator so that it always stay at the top-left of the node
  5. creates a renderer to render the tiny square. I think we can use a ShapeRenderer instead so this step could be skipped.
NEVER USE "graph.nodes.xxx.yyy.zzz" AS A GROUP'S NAME. IT BREAKS PREFUSE. I haven't had the time to figure out why, probably because of some of its internal parsing error, but this kind of names break Prefuse. I learned about this the hard way; wasted 4+ hours.