|
||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
---|---|
EdgeRenderer | An EdgeRenderer is responsible for rendering every VisEdge that comes its way |
LayoutEmitter | |
VertexRenderer |
Class Summary | |
---|---|
AbstractLayout | This class is essentially a decorator: for each vertex or edge, it must return a VisVertex or VisEdge object. |
Coordinates | Stores coordinates (X,Y) for vertices being visualized. |
CoordinateUtil | |
CoordinateUtil.Line | A class which represents a geometric line. |
EmittedLayout | |
OldToNewRenderer | This utility class converts your favorite old-style renderer into the newfangled NewGraphDraw VertexRenderer and EdgeRenderer. |
StaticLayout | |
VisEdge | This implements an edge between two points. |
VisVertex |
This module provides a new way of thinking about graph drawing. In particular, it is designed to be a great deal more flexible than the previous model, and to allow users to manage a great deal more than they once had.
At its core is a notion of the EmittedLayout. An EmittedLayout is a way of storing the current positions of a set of vertices. An EmittedLayout comes from one of two places. First, it may be generated anew from a StaticLayout. A static layout generates a layout de novo (well, from outside the graphics system): from a saved file, algorithmically, or whatever. The call "emit" to a static layout must produce a new EmittedLayout. (This need not work more than once).
Second, it may come from an animation cycle. Largely, these consist of IterableLayouts. An IterableLayout takes in a starting vertex configuration (in the form of an EmittedLayout), and is responsible for producing a new vertex configuration. When advance() is called on an iterable layout, it (presumably) moves forward one step in time. When emit() is called, the last stable copy of the data is retruned.
Note that this has several implications: First, the sequence advance() ; emit() ; emit() ; emit() should return the t=1 version of the thing three times in a row.
Second, this should be fairly thread-safe. Specifically, it should be safe to call emit() while advance() is still running. (Throughout, I assume that Advance may take a rather long time to run, and that the application should be interactive even while advance is waiting. When advance is fairly fast, some gratuitous copies of the layout may be made.)
The mechanism responsible for handling this iteration is the LayoutIterator. It repeatedly calls advance(), then sends the emitted layout to the graph panel.
The graph panel, in turn, is the usual Swing object; it iterates in a paintComponent loop. There is a subtlety here, too, but to clarify it, I must first discuss the Pipeline.
The Pipeline is the mechansim that applies any necessary distortions, twists, resizings to the graph. It consists of zero or more LayoutTransformers. A LayoutTransformer modifies (in place) an EmittedLayout to match the needs of this particular display.
The default pipeline is pre-loaded (in the LocalGraphDraw c'tor) with a FitOnScreen transformer, which expands the current visualization to take up the full screen, and the SlightMarginTransformer, which adds a small amount of space on all sides. (How can these be removed? Not easily, right now.)
So when a new layout is created by the LayoutIterator and the IterableLayout, it must be shuffled through the pipeline (in the GraphLayoutPanel). First, a copy of the layout is kept. (You'll see why in a moment). Second, it is processed through the pipeline foreward: first the FitOnScreen, then the SlightMargin, and then any others that the user has added.
What happens when the screen is resized? Two things. First, the pipeline may need to be adjusted. (Both FitOnScreen and SlightMargin, for instance, care about the dimensions of the screen). As such, a Dimension object is passed BACKWARDS through the pipeline. That is, the last object is sent that object, then the second-to-last, and so on. This allows different stages of the pipeline to constrain the area in which a previous layout could work. (This is Pipeline.adjustSizes().)
Second, the copy of the layout that we made two paragraphs back is shuffled through the pipeline. This is GraphLayoutPanel.resizeLayouts(). Good thing we had a clean copy, since every pass through the pipeline can stomp on the previous one.
Last, the new, final EmittedLayout is used for two tasks. First, it gives the locations of the vertices and edges to the renderer. ( The vertices and edges are currently drawn in a random order, although all edges will be drawn before any vertices are. Perhaps this might be fixed?) Second, it answers the function "getClosestVertex" and "getClosestEdge" mouse clicks, and thus figures out which mouse click goes with which vertex.
The vertexes and edges, incidently, are drawn by a VertexRenderer and an EdgeRenderer. The user is responsible for providing both.
So why is this system so general?
Well, because it allows a lot of very cool stuff. For example, it's possible (and easy!) to generate graphs connected by non-straight lines. Add in a CrookedLineTransformer somewhere in the pipeline, and you are pretty much set. (You'll also need a good renderer).
Want to map things in a hyperbolic space? Should be little difficulty.
Want to paint nodes green? Very easy!
What the system does NOT provide is:
Both will happen "in their own sweet time"--that is, it's the visualizations' responsibility to decide what happens with them.
|
||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |