Graph Foundation Classes for Java (GFC) ======================================= What is GFC? GFC, the Graph Foundation Classes for Java, is a set of packages for working with graphs. It includes packages for creating graph models and performing graph-theoretical computations on them. It also includes two frameworks: the Graph Drawing Framework (GDF) and the Graph Layout Framework (GLF). As the names imply, the GDF is used for drawing a graph and the GLF is used for automatic layout of a graph. ----------------------------------------------------------- Who develops GFC? The author of GFC is Christian Lenz Cesar. As frameworks, the GDF and GLF are open to contributions. The GLF in particular includes a couple of layout algorithms contributed by Daniel Tunkenlang. ----------------------------------------------------------- Which version of the Java JDK should I use? The GFC has been tested on JDK 1.1.4 and above. It should also work with JDK 1.2. ----------------------------------------------------------- How stable is GFC? The GFC core application programming interface (API) has been stable for at least one year. Only additions have been made in the recent past. The current collection of drawing and layout classes in the GDF and GLF has also been stable. Most of the activity with the GDF and GLF has been to add to the collection. ----------------------------------------------------------- Is GFC difficult to learn? As any new Java API, learning the GFC is a matter of understanding the class hierarchy and the methods available. The class hierarchy should be familiar to anyone used to working with graphs. The two ancillary frameworks are straighforward and easy to grasp. The few interfaces that define the frameworks have only a few methods. ----------------------------------------------------------- How does GFC compare with other graph APIs? Besides being 100% Java, the GFC has as its goals flexibility and extensibility. That is obtained primarily by making modeling, drawing, and automatic layout orthogonal to each other. The GDF in particular, with its notion of a "drawable plug-in", makes it easy to configure and change the appearance of the drawing. ----------------------------------------------------------- Can I program [application X] with GFC? GFC is sufficiently flexible and extensible that it can be used for almost any programming task that requires graph structures, graph-drawing and/or graph-layout. ----------------------------------------------------------- When shouldn't I use GFC? If your application is based on a complex and costly layout algorithm and in addition high interactivity is required, you may want to think implementing at least your layout algorithm in a language like C. ----------------------------------------------------------- What is the difference between GFC, GDF and GLF? For the purpose of alphaWorks, "GFC" is an umbrella name that covers the core GFC, GDF and GLF. The core GFC is the part that models and manipulates graphs. The GDF is a framework that supports graph drawing. The GLF is a framework that supports automatic graph layout. ----------------------------------------------------------- Is the core GFC a framework? No. Additions to the core GFC have to be done at the user's level through class extension. The core GFC is a architected as a conventional class library. ----------------------------------------------------------- On what systems can I run GFC? Because GFC is written in 100% Java, you only need to have Java installed on your machine. ----------------------------------------------------------- Do I have to create or change my Java CLASSPATH? Probably, unless you install the GFC packages where the Java JDK is (not recommended). If you do not use a CLASSPATH at present, set one to point to the root directory where the GFC packages are unzipped. If you use a CLASSPATH and unzip the GFC packages in a root directory already pointed to by the current CLASSPATH, then you do not have change it. If you install the GFC packages under their own root directory, then add that directory to the CLASSPATH. Read the README.TXT file that you have downloaded from alphaWorks. ----------------------------------------------------------- Is GFC thread-safe? You should assume it not to be thread safe. Despite the presence of some synchronized methods, thread-safety is not guaranteed at present. ----------------------------------------------------------- How big is the core GFC? Less than 100K. Of course, when an application that uses GFC is packaged for deployment, the unused GFC classes can be dropped to save space. ----------------------------------------------------------- How big is the GDF and GLF? The collection of "plug-ins" in GDF and GLF is constantly growing. However, because an application typically uses a couple or a few of those plug-ins, they typically do not add a lot the final size of the application. ----------------------------------------------------------- Does GFC have a year 2000 problem? Dates are not used in GFC. GFC is year-independent. ----------------------------------------------------------- What do we mean by a graph-object? "Graph-object" is the generic term for the concrete objects that make up a graph: vertices, edges and the graphs themselves. The GraphObject class is the highest level class in the GFC class hierarchy. Most other classes in the core GFC derive from that class. ----------------------------------------------------------- How is a graph modelled within GFC? A graph contains a set of vertices and a set of edges. A vertex contains a set of edges that are incident to that vertex. An edge contains a pair of vertices that are the end-points of that edge. In addition, a vertex contains a set of graphs to which that vertex belongs. An edge also contains a set of graphs to which that edge belongs. Therefore any vertex or edge can belong to more than one graph. We have two distinct situations: one in which no vertex or edge is shared between graphs, the other in which vertices and edges may be shared between graphs. ----------------------------------------------------------- What are the systemdict and userdict? The systemdict and userdict are two dictionaries that are in every graph-object instance. They are meant to store system and user data that are specific to an application. By convention, the systemdict is used by classes that are part of GFC or user-extensions thereof. The userdict is used by the application. ----------------------------------------------------------- Should I care about the systemdict and userdict? The systemdict and userdict are conveniences, and not essential to programming with GFC. Those two dictionaries are there to allow an application to store data. Alternatively the programmer can achieve the same result by means of class extensions, the latter carrying the application data. ----------------------------------------------------------- Won't using systemdict and userdict slow my application? There is an overhead associated with storing and retrieving data in dictionaries. In practice we have not found that overhead to be noticeable when the number of entries in those dictionary is small. We have run applications that used the dictionaries side by side with applications that used class extensions to store application data, and we could not measure a difference. ----------------------------------------------------------- Why are classes GraphDraw and GraphLayout sandwiched between classes GraphObject and classes Net, Vertex and Edge? To keep the story short, it is because Java does not support multiple-inheritance. If that were not the case, we would have architected a different class hierarchy. ----------------------------------------------------------- What is the difference between the Drawable, Drawable2, and Drawable3 interfaces? The Drawable3 interface is speculative and therefore we do not recommend its use at this time. The difference between the Drawable and Drawable2 interfaces is that the former is used when an application manipulates a single graph or multiple graphs that do not share graph-objects, while the latter is used when multiple graphs are involved and they share vertices and/or edges. ----------------------------------------------------------- I see interfaces called DrawableNet, DrawableEdge and DrawableVertex. What are those? At this time we would not recommend using those as they are speculative and may not survive into the next release. ----------------------------------------------------------- In the drawable collection that comes with the GDF, I see names that begin with prefixes such as DrawVertex, Draw2Vertex and Draw3Vertex. What differentiates them? By convention we name drawables DrawVertex and DrawEdge if they satisfy the Drawable interface; Draw2Vertex and Draw2Edge if they satisfy the Drawable2 interface; and Draw3Vertex and Draw3Edge if they satisfy the Drawable3 interface. Since Drawable3 extends Drawable2, and Drawable2 extends Drawable, Draw3Vertex and Draw3Edge classes are the most flexible. Most of the vertex-drawables in the collection satisfy the Drawable3 interface and therefore can be used in lieu of drawables satisfying the Drawable2 and Drawable interfaces. ----------------------------------------------------------- How do I write my own vertex-drawable? Vertex-drawables are where a significant portion of the graphical expression of a graph rendering is to be found. The multifarious ways in which one can draw a vertex means that it is likely to be one area where programmers will exercise their creativity. A vertex-drawable can be written independently of the collection that comes with the GFC distribution. It is sufficient to implement the Drawable, Drawable2 or Drawable3 interfaces. The collection provides a few abstract vertex-drawables that can give your own vertex-drawable some desirable properties. The abstract DrawVertex class provides support for painting the vertex with different alignments relative to the location of the vertex. If your vertex-drawable extends DrawVertex, you get those for free. Moreover, that abstract vertex-drawable also takes care of class checking the graph-object parameter and casting it to the Vertex class. Your vertex-drawable then only needs to implement the abstract methods that have Vertex in their signatures. That way one can concentrate on the drawing code. Similarly the Draw2Vertex class provides, among other services, a way to more finely adjust the position of a vertex before drawing. On top of the aligment provided by DrawVertex, the Draw2Vertex extension allows translations to be applied to the vertex' location. ----------------------------------------------------------- My own vertex-drawable will paint text. Are there any classes in the GDF collection that I can extend that will facilitate the creation of my vertex-drawable? The abstract vertex-drawable Draw3VertexBaseText provides methods for setting the font and color to be used for the text. Those two properties -- font and color -- are stored by the drawable and therefore apply equally to all graph-objects using it. ----------------------------------------------------------- How do I plug-in my vertex-drawable into the vertices of the graph? Using the setDrawable(Drawable)void method. For example: Drawable vd = new Draw3VertexRectangle(); Vertex v1 = new Vertex(); Vertex v2 = new Vertex(); v1.setDrawable( vd ); v2.setDrawable( vd ); ----------------------------------------------------------- Do all vertices have to use the same vertex-drawable? No. You can assign different vertex-drawables. For example: Drawable vdc = new Draw3VertexCircle(); Drawable vdr = new Draw3VertexRectangle(); Vertex v1 = new Vertex(); Vertex v2 = new Vertex(); Vertex v3 = new Vertex(); v1.setDrawable( vdc ); v2.setDrawable( vdr ); v3.setDrawable( vdc ); ----------------------------------------------------------- Can I change drawables dynamically? Sure. That's a nice feature of GFC. You can use the setDrawable(Drawable)void method any time. Note however that simply calling that method will not automatically redraw the graph. You have to ask the graph to repaint itself for you to see a change in the drawable used. For example: Drawable vdc = new Draw3VertexCircle(); Drawable vdr = new Draw3VertexRectangle(); Graph graph = new Graph(); Vertex v1 = new Vertex(); Vertex v2 = new Vertex(); graph.add( v1 ); graph.add( v2 ); Edge e12 = new Edge( v1 , v2 ); graph.add( e12 ); v1.setDrawable( vdc ); v2.setDrawable( vdc ); graph.draw(graphics); // ...later v1.setDrawable( vdr ); graph.draw(graphics); ----------------------------------------------------------- In the GraphDraw class I see three 'draw' methods. When do I use each? The primary method for drawing a graph-object is draw(Graphics)void. That method however assumes that there is no vertex or edge sharing, that is, a vertex or edge belongs to one and only graph. The application may have defined more than one graph, but the sets of vertices and edges of each are independent. That is the normal situation for the great majority of applications. When the above assumption is not valid, namely, the application has defined two or more graphs, and some vertices and/or edges are shared by two or more of those graphs, then method draw(Graphics)void will be faced with ambiguities. For example, if a vertex v1 is shared by two graphs g1 and g2, v1.draw(Graphics) is ambiguous for v1 may have two locations, one associated with g1 and another with g2. That ambiguity is resolved by using the method draw(Net,Graphcs)void. The Net parameter specifies which graph we are interested in. Therefore the call should be v1.draw(g1,graphics) and v1.draw(g2,graphics). The third signature -- draw(Dict,Graphics)void -- aims at resolving a different sort of problem. Consider for example a drawing of a graph where some vertices may be drawn more than once at different locations. The way such a situation is typically handled in GFC is to have "sub-dictionaries" for those multiple locations. By "sub-dictionary" we mean a dictionary that is stored in a systemdict and contains key/value pairs similar to the ones we normally store in systemdict, in particular the location of the graph-object. For example, if a vertex v1 in graph g is drawn twice, in two different locations, the systemdict of v1 can store two dictionaries dict1 and dict2 that describe the properties of each appearance of v1. To draw the two appearances, we call draw(dict1,graphics) followed by draw(dict2,graphics). We do not expect many applications to need that third kind of signature. In most graph drawings, every vertex and edge of a graph is painted once, at one location. ------------------------------------------------------------ In the GraphDraw class I see three 'contains' methods. When do I use each? The primary method for determining whether a graph-object contains a coordinate is contains(int,int)boolean. That method however assumes that there is no vertex or edge sharing, that is, a vertex or edge belongs to one and only graph. The application may have defined more than one graph, but the sets of vertices and edges of each are independent. That is the normal situation for the great majority of applications. When the above assumption is not valid, namely, the application has defined two or more graphs, and some vertices and/or edges are shared by two or more of those graphs, then method contains(int,int)boolean will be faced with ambiguities. For example, if a vertex v1 is shared by two graphs g1 and g2, v1.contains(x,y) is ambiguous for v1 may have two locations, one associated with g1 and another with g2. That ambiguity is resolved by using the method contains(Net,int,int)boolean. The Net parameter specifies which graph we are interested in. Therefore the call should be v1.contains(g1,x,y) or v1.contains(g2,x,y). The third signature -- contains(Dict,x,y)boolean -- aims at resolving a different sort of problem. Consider for example a drawing of a graph where some vertices may be drawn more than once at different locations. The way such a situation is typically handled in GFC is to have "sub-dictionaries" for those multiple locations. By "sub-dictionary" we mean a dictionary that is stored in a systemdict and contains key/value pairs similar to the ones we normally store in systemdict, in particular the location of the graph-object. For example, if a vertex v1 in graph g is drawn twice, in two different locations, the systemdict of v1 can store two dictionaries dict1 and dict2 that describe the properties of each appearance of v1. If we are interested in finding out whether the first appearance contains a given coordinate (x,y), we call contains(dict1,x,y); for the second, the call is contains(dict2,x,y). We do not expect many applications to need that third kind of signature. In most graph drawings, every vertex and edge of a graph is painted once, at one location. ------------------------------------------------------------ In the GraphDraw class I see three 'getBounds' methods. When do I use each? The primary method for determining the rectangular bounds of a graph-object is getBounds()java.awt.Rectangle. It applies to sizing nets (and their derivatives), vertices and edges. For vertices and edges however, that method assumes that there is no vertex or edge sharing, that is, a vertex or edge belongs to one and only graph. The application may have defined more than one graph, but the sets of vertices and edges of each are independent. That is the normal situation for the great majority of applications. When the above assumption is not valid, namely, the application has defined two or more graphs, and some vertices and/or edges are shared by two or more of those graphs, then method getBounds()java.awt.Rectangle will be faced with ambiguities. For example, if a vertex v1 is shared by two graphs g1 and g2, v1.getBounds() is ambiguous because v1 may have two locations, one associated with g1 and another with g2. That ambiguity is resolved by using the method getBounds(Net)java.awt.Rectangle. The Net parameter specifies which graph we are interested in. Therefore the call should be v1.getBounds(g1) or v1.getBounds(g2). The third signature -- getBounds(Dict)java.awt.Rectangle -- aims at resolving a different sort of problem. Consider for example a drawing of a graph where some vertices may be drawn more than once at different locations and possibly using different vertex-drawables. The way such a situation is typically handled in GFC is to have "sub-dictionaries" for those multiple locations. By "sub-dictionary" we mean a dictionary that is stored in a systemdict and contains key/value pairs similar to the ones we normally store in systemdict, in particular the location of the graph-object. For example, if a vertex v1 in graph g is drawn twice, in two different locations and using two different drawables, the systemdict of v1 can store two dictionaries dict1 and dict2 that describe the properties of each appearance of v1. If we are interested in finding out the bounds of the first appearance, we call getBounds(dict1); for the second, the call is getBounds(dict2). We do not expect many applications to need that third kind of signature. In most graph drawings, every vertex and edge of a graph is painted once, at one location. ------------------------------------------------------------ In the GraphDraw class I see three 'getSize' methods. When do I use each? The primary method for the determining the dimension of a graph-object is getSize()java.awt.Dimension. It applies to sizing nets (and their derivatives), vertices and edges. For vertices and edges however, that method assumes that there is no vertex or edge sharing, that is, a vertex or edge belongs to one and only graph. The application may have defined more than one graph, but the sets of vertices and edges of each are independent. That is the normal situation for the great majority of applications. When the above assumption is not valid, namely, the application has defined two or more graphs, and some vertices and/or edges are shared by two or more of those graphs, then method getSize()java.awt.Dimension will be faced with ambiguities. For example, if a vertex v1 is shared by two graphs g1 and g2, v1.getSize() is ambiguous because v1 may have be drawn by two different drawables , one associated with v1 in g1 and another with v1 in g2. That ambiguity is resolved by using the method getSize(Net)java.awt.Dimension. The Net parameter specifies which graph we are interested in. Therefore the call should be v1.getSize(g1) or v1.getSize(g2). The third signature -- getSize(Dict)java.awt.Dimension -- aims at resolving a different sort of problem. Consider for example a drawing of a graph where some vertices may be drawn more than once using different vertex-drawables. The way such a situation is typically handled in GFC is to have "sub-dictionaries" for those multiple drawables. By "sub-dictionary" we mean a dictionary that is stored in a systemdict and contains key/value pairs similar to the ones we normally store in systemdict, in particular the drawable and possibly ancillary drawing properties. For example, if a vertex v1 in graph g is drawn twice, in using two different drawables, the systemdict of v1 can store two dictionaries dict1 and dict2 that describe the properties of each appearance of v1. If we are interested in finding out the size of the first appearance, we call getSize(dict1); for the second, the call is getSize(dict2). We do not expect many applications to need that third kind of signature. In most graph drawings, every vertex and edge of a graph is painted once, at one location. ------------------------------------------------------------ In the GraphDraw class I see three 'setDrawable' and three 'getDrawable' methods. When do I use each? The primary accessor methods for the drawable used in painting a graph-object is setDrawable(Drawable)void and getDrawable()Drawable. Those two methods apply to nets (and their derivatives), vertices and edges. For vertex and edge-drawables however, those two methods assume that there is no vertex or edge sharing, that is, a vertex or edge belongs to one and only graph. The application may have defined more than one graph, but the sets of vertices and edges of each are independent. That is the normal situation for the great majority of applications. When the above assumption is not valid, namely, the application has defined two or more graphs, and some vertices and/or edges are shared by two or more of those graphs, then methods setDrawable(Drawable)void and getDrawable()Drawable will be faced with ambiguities. For example, if a vertex v1 is shared by two graphs g1 and g2, v1.setDrawable(Drawable) and v1.getDrawable() are potentially ambiguous because v1 may need to or may be using different drawables, one associated with g1 and another with g2. That ambiguity is resolved by using the methods setDrawable(Net,Drawable) and getDrawable(Net). The Net parameter specifies which graph we are interested in. Therefore the calls should be v1.setDrawable(g1,drawable) and v1.getDrawable(g1) for getting to the drawable used on v1 when painting g1, and v1.setDrawable(g2,drawable) and v1.getDrawable(g2) when painting g2. The third signatures -- setDrawable(Dict,Drawable)void and getDrawable(Dict)Drawable -- aim at resolving a different sort of problem. Consider for example a drawing of a graph where some vertices may be drawn more than once at different locations and using different vertex-drawables. The way such a situation is typically handled in GFC is to have "sub-dictionaries" for those multiple locations and drawables. By "sub-dictionary" we mean a dictionary that is stored in a systemdict and contains key/value pairs similar to the ones we normally store in systemdict, in particular the location of and drawable for each of the appearances of the same graph-object. For example, if a vertex v1 in graph g is drawn twice, in two different locations and using two different drawables, the systemdict of v1 can store two dictionaries dict1 and dict2 that describe the properties of each appearance of v1. If we are interested in getting to the drawable of the first appearance, we call setDrawable(dict1,drawable) and getDrawable(dict1); for the second, the calls are setDrawable(dict2,drawable) and getDrawable(dict2). We do not expect many applications to need that third kind of signature. In most graph drawings, every vertex and edge of a graph is painted once, at one location. ------------------------------------------------------------ In the GraphDraw class I see several 'setLocation' and 'getLocation' methods. When do I use each? In answering that question we confuse the (int,int) coordinate signatures with the (Point) signatures and only consider the latter. The primary accessor methods for the location of a graph-object is setLocation(java.awt.Point)void and getLocation()java.awt.Point. Those two methods however assume that there is no vertex or edge sharing, that is, a vertex or edge belongs to one and only graph. The application may have defined more than one graph, but the sets of vertices and edges of each are independent. That is the normal situation for the great majority of applications. When the above assumption is not valid, namely, the application has defined two or more graphs, and some vertices and/or edges are shared by two or more of those graphs, then methods setLocation(java.awt.Point)void and getLocation()java.awt.Point will be faced with ambiguities. For example, if a vertex v1 is shared by two graphs g1 and g2, v1.setLocation(pt) and v1.getLocation() are potentially ambiguous because v1 may have two different locations, one associated with g1 and another with g2. That ambiguity is resolved by using the methods setLocation(Net,Point) and getLocation(Net). The Net parameter specifies which graph we are interested in. Therefore the calls should be v1.setLocation(g1,pt1) and v1.getLocation(g1) for getting to the location set for v1 when considering g1, and v1.setLocation(g2,pt2) and v1.getLocation(g2) when considering g2. The third signatures -- setLocation(Dict,java.awt.Point)void and getDrawable(Dict)Drawable -- aim at resolving a different sort of problem. Consider for example a drawing of a graph where some vertices may be drawn more than once at different locations. The way such a situation is typically handled in GFC is to have "sub-dictionaries" for those multiple locations. By "sub-dictionary" we mean a dictionary that is stored in a systemdict and contains key/value pairs similar to the ones we normally store in systemdict, in particular the location of each of the appearances of the graph-object. For example, if a vertex v1 in graph g is drawn twice, at two different locations, the systemdict of v1 can store two sub-dictionaries dict1 and dict2 that describe the properties of each appearance of v1, in particular the locations. If we are interested in getting to the location of the first appearance, we call setLocation(dict1,pt1) and getLocation(dict1); for the second, the calls are setLocation(dict2,pt2) and getLocation(dict2). We do not expect many applications to need that third kind of signature. In most graph drawings, every vertex and edge of a graph is painted once, at one location. ----------------------------------------------------------- What happens within GFC when the different signatures -- method(...), method(Net,...), and method(Dict,...) -- are used? Methods that have the method(...) signature normally work off the systemdict. Methods that have the method(Net,...) signature normally work off a dictionary that is the value of a key/value pair stored in a systemdict and whose key is the Net parameter. We often call such a sub-dictionary a "net-dictionary". For example: We create a vertex v1 and add it to two graphs g1 and g2. To differentiate the properties of v1 vis a vis each graph, we create in the systemdict of v1 two key/value pairs: and . Properties of v1 that are specific to g1, we store in dict1; and those specific to g2, we store in dict2. To access the properties specific to g1, we use method(g1,...); for g2, method(g2,...). Methods that have the method(Dict,...) signature normally work off a dictionary that is directly specified by the call. That dictionary could be stored in the systemdict of a graph-object but does not have to be so. It could also be a disconnected or independent dictionary coming from anywhere in the application. The last of the three signatures is the most generic. The signature method(...) maps to method(systemdict,...) and the signature method(Net,...) maps to method(systemdict.get(net),...). ----------------------------------------------------------- If I store drawing properties in a net-dictionary do all properties associated with that net have to be stored in that dictionary? No. If a drawable looks for a property in a net-dictionary and does not find an entry in that net-dictionary for that property, the GFC will try to find such an entry in the systemdict of the graph-object. That way, you can store properties of a shared graph-object that are common across all graphs owning that graph-object in its systemdict, rather than storing identical copies in each net-dictionary. For example, if vertex v1 belongs to graphs g1 and g2, we could have the following allocation of properties: Graph g1 = new Graph(); Graph g2 = new Graph(); Vertex v1 = new Vertex(); g1.add( v1 ); g2.add( v1 ); Dict dict1 = new Dict(); Dict dict2 = new Dict(); v1.systemdict.def( g1 , dict1 ); v1.systemdict.def( g2 , dict2 ); v1.systemdict.def( "font" , new Font( Helvetica , Font.BOLD , 18 ) ); dict1.def( "color" , Color.red ); dict2.def( "color" , Color.blue ); That is, the font used when drawing v1 is stored in v1's systemdict. That means the same font is used in drawing v1 whether g1 or g2 is painted. On the other hand, the "color" property is stored in the net-dictionaries dict1 and dict2. When v1 is drawn during a paint of g1, its color is red; when painting g2, v1's color is blue. ----------------------------------------------------------- How do I find out what properties are recognized by a drawable? Properties that are stored by the drawable itself have accessor methods. Read the API documentation. Properties that are stored by the graph-object and are retrieved from its systemdict or other dictionaries through named keys can be gathered from the methods associated with the drawable class that define what the key names are. For example, the vertex-drawable Draw3VertexKeyText has the acessors getKeyText()String and setKeyText(String)void. From those two methods, one can deduce that there is a key in the vertex's systemdict with that name whose value is a text string that is used for painting that vertex. ----------------------------------------------------------- Why am I getting a NotDrawableException? The most likely cause of a NotDrawableException is forgetting to set the location of one or more vertices. The location of a vertex is either set explicitly via one of the setLocation(...) methods or implicitly via a layout algorithm. ----------------------------------------------------------- What are all those "Cached" methods in class GraphDraw? Consider them work-in-progress. The API may change. The purpose of those methods is to "cache" the location of a graph-object. That comes into play when one needs to iterate over a tentative location of a graph-object before the final location is attained. It is a situation that occurs with some graph-layout algorithms. By cacheing the location, we avoid the overhead of going through the systemdict of the object. Though that overhead is small, it can become noticeable when multiplied by algorithmic iterations. By iterating over a cached location, we keep the time needed for updating the tentative location to a minimum. When the iteration completes, the cached location is transferred to its normal place via the normal setLocation() method. ----------------------------------------------------------- Some drawable names in the GDF collection have the word "Key" in them. What does that mean? Drawables will typically support any number of graphical properties that influence how the graph-object to which they apply is painted. Properties such as color, fonts, shape sizes, annotation text, etc. may be supported by a drawable. But where do such properties get stored? In GFC there are at least two places where a property can be stored. First, it can be stored in the drawable itself. Second, it can be stored in the graph-object. These two different placements have important consequences. A property that is stored in a drawable will apply to all graph-objects that are using that drawable for painting. A property that is stored in a graph-object will apply only to that graph-object. When a property is stored in a drawable, it knows where to fetch that property. When a property is stored in a graph-object, a convention is established on where that property is stored in the graph-object for the drawable to get to that property. In GFC the often used storage area for graphical properties in a graph-object is the systemdict of that graph-object. The property is stored as key/value pair in the systemdict of the graph-object. The key is typically a string with an agreed name. To apply the property, the drawable retrieves the systemdict of the graph-object it is asked to paint, retrieves the property-name/property-value pair from the systemdict, and uses that value in rendering. When a drawable supports more than one property, some may be stored in the drawable while the others will be stored in the graph-object's systemdict or other dictionaries. A property that is significant enough we want its name to appear as part as the drawable class name will be prefixed with the word "Key" if the drawable expects to find it in the graph-object's systemdict, otherwise the property is assumed to be stored in the drawable. For example, a class named DrawSomethingProperty1KeyProperty2 indicates to the reader that Property1 is stored in the drawable and Property2 is a key/value value in the graph-object's systemdict. ----------------------------------------------------------- I don't see color accessors for a drawable. How can I set colors for filling and outlining? Some drawables are aggregations of other drawables. The aggregate typically provides methods for getting at the individual drawables that make up the aggregate. In turn the individual drawables probably have color accessor methods. For example: Draw3VertexEllipseKeyText d3vekt = new Draw3VertexEllipseKeyText(); d3v3kt.getDraw3VertexEllipse().setDoFill( Color.yellow ); d3v3kt.getDraw3VertexEllipse().setColorFill( Color.green ); (From GFC1.1.2 on, the Draw3VertexEllipseKeyText has color setting methods that are call-throughs to the ellipse component.) ----------------------------------------------------------- Do I have to set a drawable for a graph? Yes. A graph-drawable schedules the order in which vertices and edges are painted. Some graph-drawables may paint vertices and/or edge multipe times. ----------------------------------------------------------- In many examples of the use of GFC I do not see a drawable set for the graph. What is going on? There is a default graph-drawable defined for every graph. It is DrawNetEdgesThenVertices. As the name implies, that graph-drawable first paints all edges and then paints all vertices. ----------------------------------------------------------- If I change the rendering properties of a vertex, can I repaint that vertex without having to repaint the graph? Yes, by calling the method draw(Graphics) on that vertex. If the redrawing is caused by, for example, a mouse event on that vertex, the following code will do the job: vertex.draw( ((GraphCanvas)mouseevent.getComponent()).getGraphics() ); ----------------------------------------------------------- Are there any drawables in the GDF that make use of the new Java 2D API? At present no, but there are a few already being tested in the lab. In any case, the GDF allows users to develop their own drawables, in particular ones using the new features of the Java 2D API. ----------------------------------------------------------- I have written a drawable for the GDF that may be useful to others. I would like to share it with others. Suggestions? That's the idea behind the GDF. As more and more people write drawables for the GDF and they are shared with others, the larger the collection of drawables that users can choose from. If you think your drawable is general enough or addresses a common need, make it known to others through the GFC forum on alphaWorks. If it is short enough, post it to the forum directly. ----------------------------------------------------------- What is the com.ibm.graph.ext.visual package? That is an extension to the core graph-object classes that provides ready-to-use drawable graph-objects. In other words, the drawables have already been plugged-in. Use this package if you don't want to bother instantiating and plugging in drawables explicitly, and your needs for drawable is for common shapes (e.g., rectangles, ellipses, with or without text) and simple properties (e.g. colors and alignment). ----------------------------------------------------------- I have a graph-layout algorithm written in C. Can I use it with GFC? Write a wrapper class that implements the GraphLayoutManager interface and within that class implement the necessary native-interface to your C code and the conversion code from the GFC to the C program graph-representation. When the layout is done, retrieve the layout data, typically locations of vertices, and apply that data to GFC, for example, through the setLocation(java.awt.Point) method. ----------------------------------------------------------- Does the GLF support incremental layout? The GraphLayoutManager interface does not define incremental layout methods at present. Only batch. That does not however prevent a layout algorithm from implementing methods for such a purpose, methods an application can call directly, thus bypassing the usual GFC layout() method. An incremental layout extension to the above interface is under construction. ----------------------------------------------------------- Are graph-drawables and graph-layout-algorithms always orthogonal to each other? Unfortunately not. Not every graph-drawable is compatible with every graph-layout-algorithms, though they often are. For example, the LayoutGraphAsTree layout-manager requires a specialized graph-drawable, namely and not too surprisingly, DrawNetForLayoutGraphAsTree. The reason is that that layout manager requires some vertices and edges to be painted more than once at different locations. The graph-drawable must therefore have that capability and be able to recognize which vertices and edges are painted multiple times and how to get to the corresponding locations. ----------------------------------------------------------- What class should I use to build a graph-canvas on which to paint and interact with my graphs? The primary AWT-based class for helping you build your graph-drawing application is com.ibm.graph.awt.GraphCanvas. ----------------------------------------------------------- How do I implement drag-and-drop? The class GraphCanvas provides GraphCanvasEvents that allow one to track mouse events. Implement a GraphCanvasEventListener that tracks mouse dragged events. GDFEx26.java is an example of one way to do it. ----------------------------------------------------------- What is the relation between com.ibm.graph.awt.GraphEvent and com.ibm.graph.awt.event.GraphCanvasEvent? The first has been deprecated. In a future release of GFC its meaning will change to that of a graph model event. The second represents events that arise from interactions with a com.ibm.graph.awt.GraphCanvas and should be the one used. ----------------------------------------------------------- What are the classes GraphCanvasEvents and GraphCanvasDragAndDrop in package com.ibm.graph.awt? Those were early and incomplete implementations of graph-canvas support. They are deprecated and should disappear or be reorganized in a future release of GFC. ----------------------------------------------------------- Why is com.ibm.graph.awt.GraphEventListener deprecated? Unfortunately, that interface was used during an early stage of development for describing listeners on events coming from a graph-canvas. In a future release that interface will serve a different purpose, namely, listening on events arising from changes to a graph model. The correct interface to use is com.ibm.graph.awt.event.GraphCanvasEventListener. ----------------------------------------------------------- How do I get mouse coordinates from a graph-canvas-event? The method GraphCanvasEvent.getAWTEvent() returns a java.awt.AWTEvent, that is in fact a java.awt.event.MouseEvent. Cast the java.awt.AWTEvent to a java.awt.event.MouseEvent and use the method getPoint(). ----------------------------------------------------------- How do I debug a program that uses GFC? Some GFC classes have a "verbose" flag that can provide useful information. That flag is controlled via accessor methods. Moreover the toString() method is implemented for almost every class in GFC and it too can provide information about graph-objects. ----------------------------------------------------------- Where do I send a bug report? You can post a bug report on the alphaWorks GFC forum or send an email to the author: cesar@us.ibm.com. ----------------------------------------------------------- How can I reach the author? Email him at cesar@us.ibm.com. ----------------------------------------------------------- Latest revision 2000 July 18.