The Diva canvas

Package:

diva.canvas

Author:

John Reekie

Status:

Version 0.3. Re-reviewed by Neil Smyth.
Version 0.2.1. Tidying and moving stuff around. Design review by Neil Smyth and Ron Galicia.
Version 0.2. Second draft. Changes. Published to ptdesign. 05/05/98.
Version 0.1. Initial comments requested from the Java 2D mailing list. 05/01/98.

Sub-packages:


diva.canvas.animation
diva.canvas.collection
diva.canvas.decorators
diva.canvas.event
diva.canvas.feature
diva.canvas.figures
diva.canvas.interactors
diva.canvas.swing

Imported packages and classes:

java.awt.*
java.awt.geom.*
java.awt.event.*
java.util.List
java.util.Collection
diva.canvas.event.EventDispatcher
diva.canvas.feature.FeatureSet

See also:

Copyright

Contents

Overview

The Diva canvas is implemented on top of the Java 2D API, and provides a construction toolkit for interactive 2D viewers and editors. It is not a drawing package. Its design is based on our experiences with interactive editors and our goals for future work that takes advantage of the 2D support in provided by the Java 2D API.

The key concepts in this package are as follows:

Figures
A figure is a graphical item drawn on an AWT canvas. Figures are constructed hierarchically -- they thus form a tree. Figures are retained-mode objects -- for example, you can ask a figure to move, and it will redraw itself in the new location.

Features
Each figure has a set of features, which are points of interest on the figure. A rectangular shape, for example, would have a feature set that includes (at least) the four corners. Other figures can choose to define their own set -- for example, a figure used to represent a terminal in a dataflow diagram may have a feature for the attachment point.

Layers
A layer is a logical grouping of a set of figures. A layer acts as a kind of light-weight canvas, and can have a subset of the same event listeners as JCanvas. Each layer maintains its own local coordinate system, and can have a selection associated with it. The top level of the canvas is implemented as one or more root layers.

Glass
A glass is both a layer and a figure that is clipped to a region of the canvas and that has a transparent or translucent background. (The name is inspired by Xerox PARCs toolglasses.) Glasses are used to implement multiple, overlapping, regions of the canvas. Conceptually, at least, glass can be used to implement overlapping layers and portals (DataSplash), magic lenses and tool glasses (Stone, Bier), translucent overlapping workspaces (Kramer), as well as regular old overlapping windows.

Events
The Diva canvas extends AWT's delegation-based event model to figures. Each figure can have event listeners attached to it, which will be notified when the dispatcher decides that an event belongs to this figure. Events will be passed up the figure hierarchy until consumed.

In the following, methods are only shown the first time they occur in a hierarchy. For example, add is shown in FigureContainer, but not in Layer (which extends FigureContainer) or RootLayer (which implements FigureContainer).

The canvas, panes, and layers

The canvas is composed of a canvas pane, which in turn is composed of one or more layers. Each layer may contain arbitrary graphics, although commonly at least one layer is an instance of a "figure layer" class that contains figure objects. The main role of the JCanvas class is to provide the physical screen space on which layers draw themselves, and to interface to the Swing component hierarchy.

This architecture allows a graphics developer to write code for a pane and a set of layers, without being concerned about whether the pane and its layers will be directly contained by a JCanvas or within some other layer. For example, it will be possible for a visualization component to be "embedded" in a larger component.

class JCanvas extends java.awt.swing.JComponent
The canvas is the Swing component that is used to contain figures. Its main purpose is to provide a piece of physical screen real-estate that contains a top-level CanvasPane.

JCanvas ( )
Create a new canvas that contains a single CanvasPane, which in turn contains a single FigureLayer. This is the simplest way of using the JCanvas.

JCanvas ( CanvasPane )
Create a new canvas that contains the given CanvasPane. This should be used if you need to make a canvas pane that contains more than a single layer.

CanvasPane getCanvasPane ( )
Get the canvas pane contained by this component.

void paint ( Graphics )
void paint ( Graphics, Rectangle2D )
Paint the canvas. In versions with additional arguments, the arguments are the damaged region of the canvas. This will be passed to the paint method of the contained canvas pane and have to its layers, so that they can optimize the paint to paint only the given region.

void repaint ( )
void repaint ( Rectangle2D )
void repaint ( long tm, int z, int y, int w, int h )
Schedule a repaint of the canvas. In the versions with additional arguments, the additional arguments represent the damaged region of the canvas, which is selectively merged with existing damage regions. These methods override methods inherited from java.awt.Component and java.awt.swing.JComponent.

void setCanvasPane ( CanvasPane )
Set the canvas pane contained by this component.

interface TransformedComponent
A transformed component is any component that maps "logical" internal coordinates to "absolute" screen coordinates using an instance of AffineTransform. It is used for components that can scale themselves. Logical coordinates can be integer or floating-point, whereas screen coordinates are always integer. Methods in the interface convert screen coordinates to logical coordinates and vice-versa. Note that the transform can be read (and modified, in which case this interface does not define the behavior), but cannot be set.

Point2D fromScreen ( Point2D )
Rectangle2D fromScreen ( Rectangle2D )
Shape fromScreen ( Shape )
Convert screen coordinates into logical coordinates. If this object does not return true for the isOrthogonal method, then the Rectangle2D version of this method will throw an exception, since a rectangle cannot be mapped into a rectangle in the presence of rotation or shear. If the transformation produces a non-integer value, then the value will not be truncated or rounded to the nearest integer -- it is the responsibility of the client to check for this if it's important.

JCanvas getCanvas ( )
Get the canvas that this pane lives in. This will be null if the pane hasn't been put into a canvas yet (with JCanvas.setCanvasPane()), or has been removed from a canvas.

AffineTransform getTransform ( )
Get the transform that maps logical coordinates into screen coordinates. If the tranform is null, then the mapping is one-to-one.

AffineTransform getInverseTransform ( )
Get the transform that maps coordinates into logical coordinates. If the tranform is null, then the mapping is one-to-one.

boolean isOrthogonal ( )
Return true if a rectangle in logical coordinates can be mapped to a rectangle on the screen (and vice versa).

Point2D toScreen ( Point2D )
Rectangle2D toScreen ( Rectangle2D )
Shape toScreen ( Shape )
Convert logical coordinates into screen coordinates. If this objects does not return true for the isOrthogonal method, then the Rectangle2D version of this method will throw an exception, since a rectangle cannot be mapped into a rectangle in the presence of rotation or shear.

abstract class CanvasPane implements TransformedComponent
A canvas pane groups canvas layers. The layers all share the same logical-to-screen transform as the canvas pane. This is an abstract superclass of all canvas panes, and provides the implementation of everything related to panes but the storage of the layers. Subclasses must provide methods to add and (possibly) reorder and remove layers.

abstract Iterator layers ( )
Return an iteration of the layers, in redraw order (that is, from back to front).

abstract Iterator layersFromFront ( )
Return an iteration of the layers, in event-processing order (that is, from front to back).

void paint ( Graphics2D )
void paint ( Graphics2D, Rectangle2D )
Paint the pan. Note that the graphics object must be an instance of java.awt.Graphics2D, not java.awt.Graphics. These methods forward the paint request to each layer, in redraw order.

void processEvent ( EventObject )
Process an event that has occured on the pane. Coordinates in the event object will be in layer (logical) for canvas layer events (see the package diva.canvas.event), and in screen coordinates for other event types. This implementation passes the event to each layer, from lowest to highest index. After each layer, the pane checks whether the event has been consumed, and returns if so. Subclasses can choose to override this behavior.

void repaint ( )
void repaint ( Rectangle2D )
void repaint ( long tm, int z, int y, int w, int h )
Schedule a repaint of the pane. These methods mimic the repaint methods in JCanvas. Each converts coordinates from logical coordinates to absolute coordinates if necessary, and forwards the repaint request to the containing canvas.

void setTranform ( AffineTransform )
Set the transform that maps logical coordinates into screen coordinates. Setting it to null makes the mapping one-to-one.

class BasicCanvasPane extends CanvasPane
A basic implementation of a canvas pane, provided for simple applications. This class keeps a linear list of canvas layers, and provides a couple of methods so that layers can be added to it. Real applications will probably want to create their own CanvasPane subclass, instead of using this class.

void addLayer ( CanvasLayer )
Add the given layer to the end of the list of layers. The new layer will be drawn over the top of any existing layers.

Iterator layers ( )
Return an iteration of the layers, in redraw order (that is, from back to front).

Iterator layersFromFront ( )
Return an iteration of the layers, in event-processing order (that is, from front to back).

void removeLayer ( CanvasLayer )
Remove the given layer. Do nothing if the layer is not contained in this pane.

abstract class CanvasLayer implements TransformedComponent, LayerEventSource
A canvas layer is a single layer on which figures can be drawn. Layers can be made visible or not, and can contain any arbitary graphics (i.e. not necessarily Figures).

boolean isVisible ( )
Test the visibility flag of this layer.

abstract void paint ( Graphics2D )
abstract void paint ( Graphics2D, Rectangle2D )
Paint the layer. Note that the graphics object must be an instance of java.awt.Graphics2D, not java.awt.Graphics. These abstract methods muct be overridden by concrete subclasses to check for visibility, and then paint the layer's contents.

abstract void processEvent ( EventObject )
Process an event that has occured on this layer. Coordinates in the event object will be in layer (logical) coordinates for canvas events (see diva.canvas.event), and in screen coordinates otherwise.

void repaint ( )
void repaint ( Rectangle2D )
void repaint ( long tm, int z, int y, int w, int h )
Schedule a repaint of the layer. These methods forward the repaint request to the containing pane.

void setVisible ( boolean )
Set the visibility flag of this layer. If the flag is false, then the layer will not be drawn on the screen and it will not respond to user input events.

interface FigureContainer
An interface implemented by objects that contain figures. The container can have figures added to or removed from it, and can be queried for its contents.

void add ( Figure )
Add a figure to the container's children. This interface does not define where the new figure will be in the display order (i.e. at the top, bottom, or somewhere else), although implementations may define this.

Iterator figures ( )
Return an iteration of the figures in this container, from highest index to lowest index. This is the order in which figures should normally be painted, so that figures at lower indexes are painted over the top of figures at higher indexes.

Iterator figuresFromFront ( )
Return an iteration of the figures in this container, from lowest index to highest index. This is the order in which events should normally be intercepted.

void remove ( Figure )
Remove a figure from this container.

interface ZList extends FigureContainer
A ZList is an interface for objects that contain an ordered list of figures in z-order. In addition to the methods inherited from FigureChildren, ZList has methods for reordering figures in the list, and in the future may have methods for locating objects in 2D space. This interface is used to isolate the implementation of figure containers from the z-list, to allow future optimization of the z-list implementation.

This interface tries to mimic the AWT Container and Swing JLayerPane interfaces where possible. Unfortunately, these two classes differ on the relation between list ordering and display ordering, so we have chosen to use the AWT Container order (high-numbered elements are displayed below lower-numbered elements), since we thought it would make using the add method less error-prone.

void add ( int, Figure )
Insert a figure at the given position. To insert the figure just in front of some other figure, use getIndex to get the other figure's index, and call add with index as the index argument. To insert the figure just behind some other figure, call add with index+1 as the index argument. To insert so the figure displays over the top of other figures, insert at zero. Following AWT convention, the index -1 means to add the component at the end of the list.

Iterator figuresOverlapping (Rectangle2D region)
Return an iteration of the figures in this container that overlap the given rectangle, from highest index to lowest index. This is the order in which figures are normally painted, so that figures at lower indexes overlap figures at higher indexes.

Iterator figuresOverlappingFromFront (Rectangle2D region)
Return an iteration of the figures in this container that overlap the given rectangle, from lowest index to highest index. This is the order in which events are normally intercepted.

Figure get ( int )
Return the figure at the given index.

int indexOf ( Figure )
Return the index of the given figure in the Z-list. Figures with a higher index are drawn behind figures with a lower index.

void remove ( int )
Remove the figure at the given position in the list.

void setIndex ( int, Figure )
Set the index of the given figure -- in other words, move it in the display list to the given position. To move the figure to just in front of some other figure, use getIndex to get the other figure's index, and call setIndex with index as the index argument. To move the figure to just behind some other figure, call setIndex with index+1 as the index argument. (Other figures will have their indexes changed accordingly.)

class BasicZList implements ZList
A basic implementation of the figure z-list, provided for initial implementations of figure containers.

class FigureLayer extends CanvasLayer implements ZList
A figure layer is a canvas layer that contains figures. This is the main class that is accessed when figures are drawn.

FigureLayer ( )
Create a new figure layer that is not in a pane. The layer will not be displayed, and its coordinate tranformation will be as though it were a one-to-one mapping. Use of this constructor is strongly discouraged, as many of the geometry-related methods expect to see a pane.

FigureLayer ( CanvasPane )
Create a new figure layer within the given pane.

FigureLayer ( CanvasPane, ZList )
Create a new figure layer within the given pane and with the given ZList to hold the figures it contains.

FigureLayer ( ZList )
Create a new figure layer with the given ZList to hold its figures. This can be used to create a more efficient z-list than the default, which is an instance of BasicZList.

Figures

A figure is a persistent representation of one or more Java 2D shapes. A figure have methods that deal with its screen representation, methods that deal with its position in the hierarchy, and methods that deal with its interaction with the canvas and other objects.

Figures form a hierarchy -- they are a classic example of the Composite design pattern.

interface FilledFigure
An interface that can be implemented by classes that are identifiable in some way with a single shape, either as their main component or as some kind of outline or background.

Composite getComposite ( )
Get the color composition operator of this figure.

Paint getFillPaint ( )
Get the fill paint pattern of this figure.

Shape getShape ( )
Get the shape of this figure.

void setComposite ( Composite )
Set the color composition operator of this figure. The compositioning applies to the fill only.

void setFillPaint ( Paint )
Set the fill paint pattern of this figure. The figure will be filled with this paint pattern. If no pattern is given, do not fill it.

void setShape ( Shape )
Set the shape of this figure.

interface StrokedFigure
An interface for figures that have a stroke.

Shape getShape ( )
Get the shape of this figure.

Stroke getStroke ( )
Get the stroke of this figure.

Paint getStrokePaint ( )
Get the stroke paint pattern of this figure.

void setShape ( Shape )
Set the shape of this figure.

void setStroke ( Stroke )
Set the stroke of this figure.

void setStrokePaint ( Paint )
Set the stroke paint pattern of this figure.

abstract class Figure
Figure is an abstract class that roots all figures drawn on a FigureCanvas. Sub-classes define a screen representation. Figures must not cause themselves to repaint in response to an operation (such as translate) -- repaint must be initiated explicitly by the client by a call to the canvas' repaint method.

boolean contains ( Point2D )
Test whether this figure contains the point given. The point given is in layer coordinates.

Rectangle2D getBounds ( )
Get the bounding box of this figure. The result rectangle is given in layer coordinates.

EventDispatcher getEventDispatcher ( )
Return the event dipatcher attached to this figure. Return null if there isn't one.

FeatureSet getFeatureSet ( )
Return the set of features of this figure. This method can return null if the figure doesn't support any features.

Layer getLayer ( )
Get the most immediate layer containing this figure.

Object getModel ( )
Get the model that this figure represents. Return null if there is no model.

Shape getOutline ( )
Get the outline shape of this figure. The outline shape is used for things like highlighting. The result shape is given in layer coordinates.

FigureContainer getParent ( )
Return the parent of this figure. Return null if the figure does not have a parent. (Note that a figure with no parent can exist, but it will not be displayed, as it must be in a layer for the figure canvas to ever call its paint method.

abstract boolean hasChildren ( )
Return true if this figure has child figures, otherwise false.

boolean hit ( Rectangle2D )
Test if this figure intersects the given rectangle, and the interior of the figure is not transparent to hits. This is the same as intersects if the interior of the figure is not transparent. The rectangle is given in layer coordinates.

boolean intersects ( Rectangle2D )
Test if this figure intersects the given rectangle. The rectangle is given in layer coordinates.

boolean isVisible ( )
Test the visibility flag of this figure. Note that this flag does not indicate whether the figure is actually visible on the screen, as one if its ancestors may not be visible.

abstract void paint ( Graphics2D )
abstract void paint ( Graphics2D, Rectangle2D )
Repaint the figure. If a rectangle is given, the figure should use the rectangle to optimize redraw. The redrawing will be clipped to the rectangle. The rectangle is given in layer coordinates.

void repaint ( )
Schedule a repaint of the figure. This should be called after performing modifications on the figure, so that the figure is scheduled for redrawing.

void setEventDispatcher ( EventDispatcher )
Set the event dispatcher for this figure. Once a figure has an event dispatcher attached to it, it will respond to events that occur on the figure canvas. The events that it responds to is determined by the current state of the event dispatcher.

void setModel ( Object )
Often, a figure represents some underlying information. This methods sets an object that can be retrieved with the getModel method, that is intended for use as a reference to the semantic model.

protected void setParent ( CompositeFigure )
Set the parent of this figure. If the figure already has a parent, the new parent will silently replace the old one -- this allows this method to propagate the layer information down a tree. If the argument is null, then the figure is being informed that it has been removed from its parent.

void setVisible ( boolean )
Set the visibility flag of this figure. If the flag is false, then the figure will not be drawn on the screen and it will not respond to user input events.

void transform ( AffineTransform )
Transform the figure with the supplied transform. This can be used to perform arbitrary translation, scaling, shearing, and rotation operations.

void translate ( double, double )
Move the figure the indicated distance.

abstract class LeafFigure extends Figure
A leaf figure is a figure that contains no children. This kind of figure contains one or more instances of Shape, which it uses to render itself and perform hit detection. (Leaf figures can in fact contain other figures, but rendering must be initiated "manually.") This class must be subclassed to produce concrete figures.

boolean hasChildren ( )
Always returns false.

class CompositeFigure extends Figure implements FigureContainer
A composite figure is a figure that contains child figures. On its own, this class implements a simple visible collection of figures. It can be subclassed to produce specific kinds of composite figure.

CompositeFigure ( )
Create a new composite figure containing no figures.

CompositeFigure ( FigureSet )
Create a new composite figure containing the given figures. An exception will be thrown if any figure already has a parent.

class SimpleFigure extends LeafFigure implements FilledFigure, StrokedFigure
A simple figure is one that contains a single instance of Shape. There are few convenience subclasses of this class, as in general it is better to just create them on-the-fly.

SimpleFigure ( Shape )
Create a new figure with the given shape. The figure, by default, has the unit-width continuous stroke and no paint pattern.

SimpleFigure ( Shape, Stroke )
Create a new figure with the given shape and stroke. The figure, by default, has no paint pattern.

SimpleFigure ( Shape, Paint )
Create a new figure with the given paint pattern. The figure, by default, has no stroke.

SimpleFigure ( Shape, Paint, Stroke )
Create a new figure with the given paint pattern and stroke.

class ImageFigure extends LeafFigure
An image figure contains an image that can be efficiently blitted to the screen. Image figures can be used to efficiently make multiple figures, each containing a reference to a single image. When an image figure is constructed with an image figure passed as argument, it simply creates a reference to the image in that figure. If any other figure is passed as an argument, the new figure takes a "snapshot" of that figure.

ImageFigure ( Image )
Create a new figure containing the given image.

ImageFigure ( Figure )
Create a new figure containing an image snapshot of the given figure. If the figure is an fact an image figure, then just use its image.

Image getImage ( )
Get the image contained in this figure.

void setImage ( Image )
Set the image contained in this figure.

Glass

Glass is a special kind of figure, that is also a layer. It is a kind of "light-weight, see-through canvas" within a canvas. Glass implements the FilledFigure interface for its overall shape and background. A glass maintains a transform that can be altered at any time (the simpler figures apply the transform immediately if a transform is requested). This means that stroke widths, font sizes, and paint patterns are scaled by scaling transformations. (I think.)

class Glass extends AbstractFigure implements Layer, FilledFigure
Glass is a concrete class, that, in effect, implements a light-weight canvas within a canvas. Glasses can of course be nested within each other.

Glass ( Shape )
Create a new glass with the given shape. The shape is given in layer coordinates.

void addMouseListener ( MouseListener )
Add a standard AWT mouse listener to this glass.

void addMouseMotionListener ( MouseMotionListener )
Add a standard AWT mouse motion listener to this glass.

void removeMouseListener ( MouseListener )
Remove a standard AWT mouse listener from this glass.

void removeMouseMotionListener ( MouseMotionListener )
Remove a standard AWT mouse motion listener from this glass.

Issues

Text figures
Focus
Key events
Embedded widgets
Swing compatibility