You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by Ch...@daifukuamerica.com on 2004/07/22 19:22:24 UTC
using JSVGCanvas to draw somewhere else
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?
Re: using JSVGCanvas to draw somewhere else
Posted by Thomas DeWeese <Th...@Kodak.com>.
Tonny Kohar wrote:
>>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.)
I suspect this is caused by loading the SVG before the JSVGCanvas
has a size. If the canvas doesn't have a size (or size is zero) it
set's it's size to 1 for purposes of calculating the viewing
transform.
This raises the other issue I was going to mention which is the
JSVGCanvas may not be what you want to be using here. A better
match might be to use the batik.transcoder.SVGAbstractTranscoder.
This will build the GVT tree and set the viewing transform in a
bit lighter weight manner - and also probably easier to understand.
> It maybe because the viewbox or transform stuff. Try to calculate the
> bounds by applying the transform of graphicsNode.getGlobalTransform()
> eg:
> Shape shape = (Shape)graphicsNode.getBounds();
> AffineTransform at = graphicsNode.getGlobalTransform()
> shape = at.createTransformedShape(shape);
> Rectangle bounds = shape.getBounds();
>
> Regards
> Tonny Kohar
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org
Re: using JSVGCanvas to draw somewhere else
Posted by Tonny Kohar <to...@kiyut.com>.
Hi,
> 1) Why does JSVGCanvas.getGraphicsNode()sometimes return null, at
> first. What event must I wait on to be sure that the data is
> available?
I think you can wait for GVT listener specially rendererComplete. Hope
it solve your problem.
> 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.)
It maybe because the viewbox or transform stuff. Try to calculate the
bounds by applying the transform of graphicsNode.getGlobalTransform()
eg:
Shape shape = (Shape)graphicsNode.getBounds();
AffineTransform at = graphicsNode.getGlobalTransform()
shape = at.createTransformedShape(shape);
Rectangle bounds = shape.getBounds();
Regards
Tonny Kohar
--
Sketsa
SVG Graphics Editor
http://www.kiyut.com
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-users-help@xml.apache.org