xmlgraphics-batik-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Charlton_R...@daifukuamerica.com
Subject using JSVGCanvas to draw somewhere else
Date Thu, 22 Jul 2004 17:22:24 GMT
Hello, fellow vector graphics pioneers.
First the questions:
1) Why does JSVGCanvas.getGraphicsNode() sometimes return null, at first. 
What event must I wait on to be sure that the data is available?
2) Why does GraphicsNode.getBounds() sometimes return really tiny 
rectangles? (Drawing many of the sample SVGs included with Batik renders 
them in a 1 or 2 pixel box, and I have to zoom the hell out of the 
transform in order to see anything. Still, other SVG samples display at 
the proper size.)
Now the details:
I am developing a graphical application which displays a Figure, where a 
Figure comprises a set of Doodles. Each Doodle is an independent object 
that can be programmatically added to or removed from the Figure. There 
are ShapeDoodles, TextDoodles, ImageDoodles, and various other sorts of 
Doodles, depending on what the Figure needs to display. Each Doodle 
implements the Doodle interface. The relevant part of this interface is 
shown below:
/**
 * Individual component in a figure.
 *
 * <p><b>Details:</b> A <code>Doodle</code> is a single, independent

component
 * of a {@link Figure}.  Each doodle defines its boundaries, appearance, 
and
 * relative depth in the figure.</p>
*/
public interface Doodle
{

    /**
     * Renders doodle.
     *
     * <p><b>Details:</b> <code>draw</code> renders this doodle
using the
     * supplied graphics environment.  When the host {@link FigureView} is
     * repainting itself, it will probably call this method, albeit 
indirectly,
     * to redraw its figure's components.  This method returns 
<code>true</code>
     * if drawing was successful, <code>false</code> otherwise.</p>
     *
     * @param ipG the graphics context
     * @return true iff drawing was successful
     */
    boolean draw(Graphics2D ipG);

    /**
     * Returns rectangular extent.
     *
     * <p><b>Details: </b> This method returns the rectangular extent of

this
     * <code>Doodle</code>. The rectangle returned is in logical (i.e.
     * figure) units, not display units.</p>
     *
     * @return the extent
     */
    Rectangle2D getBounds();

}

As you may have guessed, I am developing an implementation of Doodle that 
renders SVG documents. A portion of my experimental implementation is 
shown below:
public class SvgDoodle implements Doodle
{

    private GraphicsNode mpGraphicsNode;

    public SvgDoodle(SVGDocument ipDocument)
    {
        JSVGCanvas vpCanvas = new JSVGCanvas();
        GvtTreeBuilderWaiter vpWaiter = new GvtTreeBuilderWaiter();
        vpCanvas.addGVTTreeBuilderListener(vpWaiter);
        vpCanvas.setDocument(ipDocument);
        vpWaiter.waitForResult();
        mpGraphicsNode = vpCanvas.getGraphicsNode();
        // What a hack!  This is horrible and needs to be fixed.
        while (mpGraphicsNode == null)
        {
            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException ee)
            {
            }
            mpGraphicsNode = vpCanvas.getGraphicsNode();
        }
    }

    public boolean draw(Graphics2D ipG)
    {
        mpGraphicsNode.paint(ipG);
    }

    public Rectangle2D getBounds()
    {
        return mpGraphicsNode.getBounds();
    }

}

The class GvtTreeBuilderWaiter is implemented as follows:
/**
 * Waits for GVT tree builder's final state.
 *
 * <p><b>Details:</b> This class listens to a GVT tree builder and tracks

the
 * tree's build state.  The utility of this class lies entirely in
 * {@link #waitForResult()}, which blocks and does not return until the 
tree
 * builder reaches its final state.</p>
*/
public class GvtTreeBuilderWaiter implements GVTTreeBuilderListener
{

    // Note: The values of the BUILD_* constants are not arbitrary.  Keep 
them
    // in the same numerical order.

    public static final int BUILD_STARTED = 1;

    public static final int BUILD_COMPLETED = 2;

    public static final int BUILD_CANCELLED = 3;

    public static final int BUILD_FAILED = 4;

    private int mnResult = 0;

    public void gvtBuildStarted(GVTTreeBuilderEvent ipIgnored)
    {
        mnResult = BUILD_STARTED;
    }

    public synchronized void gvtBuildCompleted(GVTTreeBuilderEvent 
ipIgnored)
    {
        mnResult = BUILD_COMPLETED;
        notifyAll();
    }

    public synchronized void gvtBuildCancelled(GVTTreeBuilderEvent 
ipIgnored)
    {
        mnResult = BUILD_CANCELLED;
        notifyAll();
    }

    public synchronized void gvtBuildFailed(GVTTreeBuilderEvent ipIgnored)
    {
        mnResult = BUILD_FAILED;
        notifyAll();
    }

    public synchronized boolean waitForResult()
    {
        while (mnResult < BUILD_COMPLETED)
            try
            {
                wait();
            }
            catch (InterruptedException ee)
            {
                return false;
            }
        return true;
    }

}

The bottom line is, I simply need a way to convert a URL into an object 
that has the following methods:
1.      a method that paints to any Graphics2D I supply
2.      a method that returns the document's rectangular bounds
The code shown above only works about half the time. Any ideas?
Mime
View raw message