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 André Ávila <as...@nextech.com.br> on 2006/04/11 23:28:01 UTC

Synchronizing JSVGCanvas - Again

Hello,

I have two JSVGCanvas, one on top of the other. The bottom JSVGCanvas is used for displaying an SVG document. The upper is used as an overlay for drawing. They are both transparent.

The ultimate goal is to turn the user drawing into an SVG, but I won't do that until the user asks, so basically I have a buch of Shape objects hanging around in memory. No problem so far. The SVG drawing is just sitting there, in the bottom canvas, with a bunch of shapes drawn on the upper canvas.

Things get nasty when the user tries to interact with the SVG canvas. Following some ideas discussed with Thomas a while ago, I overwrite setRenderingTransform() and setPaintingTransform() in the SVG canvas and propagate the current transform to the overlay canvas. Since the overlay canvas just has a bunch of Shapes all I have to do is apply the same transform to its graphics context to make the Shapes move or zoom with the SVG canvas. Below is the paint() method of the overlay canvas.

public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D)g;
    
    AffineTransform at = getPaintingTransform();    // Get the transform applied in the SVG canvas (user is interacting with it)
    
    if (at != null) {
        g2d.transform(at);    // Applies the transform to the overlay graphics context
    }
    drawShapes(g2d);    // Redraws all shapes using the transformed context
 }

However, the final result does not look good: it always looks like the overlay canvas is a few milliseconds behind, as if it was waiting for the SVG canvas to render before redrawing. So, when you pan, it looks like the overlay is trying to catch up with the SVG.

Is there a better form of synchronizing the overlay? I'd like to reach the same effect as the SelectionOverlay in TextSelectionManager.

Many thanks for any ideas!

Re: Synchronizing JSVGCanvas - Again

Posted by André Ávila <as...@nextech.com.br>.
Got it, Thomas.

I was sure you would write only a few lines and make things as clear as
(clean) water. :)

Again, many thanks for your invaluable help!



> Hi Andre,
>
> André Ávila <as...@nextech.com.br> wrote on 04/12/2006 02:54:47 PM:
>
> > Anyway, I thought that pan interaction changed only the painting
> transform,
> > since is just repositioning a bitmap. So, what is the difference between
> > rendering and painting transform? Why do we need both?
>
>    The painting transform is used when doing 'interactive' changes
> to the transform (like dragging, or zooming, or rotating) to display
> the offscreen buffer providing quick feedback but once the interactive
> updates are done the document is re-rendered with the result of
> concatenating the rendering transform and the painting transform.
>
>    So the painting transform is used when 'painting' the display
> with the most recently rendered offscreen bitmap version of the
> SVG document.
>
>    The rendering transform is used when rendering the SVG document
> to the offscreen bitmap.
>
>
> > ----- Original Message ----- 
> > From: <th...@kodak.com>
> > To: <ba...@xmlgraphics.apache.org>
> > Cc: <ba...@xmlgraphics.apache.org>
> > Sent: Wednesday, April 12, 2006 3:37 PM
> > Subject: Re: Synchronizing JSVGCanvas - Again
> >
> >
> > > Hi Andre,
> > >
> > > André Ávila <as...@nextech.com.br> wrote on 04/12/2006 02:08:14 PM:
> > >
> > > > I add my DrawOverlay to it, drawing
> > > > only a standard rectangle. When I try to pan the image, the
> rectangle
> > > goes
> > > > off on its own. If you would spare a few minutes on this, you could
> > > easily
> > > > reproduce this behavior using the following code:
> > > >
> > > >  private class DrawOverlay implements Overlay {
> > > >
> > > >     Shape rect = new Rectangle2D.Double(200,200,100,100);
> > > >
> > > >     public void paint(Graphics g) {
> > > >         AffineTransform at = getPaintingTransform();
> > >
> > >    This should be:
> > >         AffineTransform at = getRenderingTransform();
> > >
> > >    The painting transform (if any) has actually already been applied
> for
> > > you.
> > >
> > > > It's a bit strange, because it is essentially the same code as in
> > > > TextSelectionManager.SelectionOverlay.paint(). What am I missing?
> > >
> > >    The TextSelectionManager uses getRenderingTransform not
> > > getPaintingTransform().
> > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> > > For additional commands, e-mail:
> batik-users-help@xmlgraphics.apache.org
> > >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> > For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by th...@kodak.com.
Hi Andre,

André Ávila <as...@nextech.com.br> wrote on 04/12/2006 02:54:47 PM:

> Anyway, I thought that pan interaction changed only the painting 
transform,
> since is just repositioning a bitmap. So, what is the difference between
> rendering and painting transform? Why do we need both?

   The painting transform is used when doing 'interactive' changes
to the transform (like dragging, or zooming, or rotating) to display
the offscreen buffer providing quick feedback but once the interactive 
updates are done the document is re-rendered with the result of
concatenating the rendering transform and the painting transform.

   So the painting transform is used when 'painting' the display
with the most recently rendered offscreen bitmap version of the 
SVG document.

   The rendering transform is used when rendering the SVG document
to the offscreen bitmap.


> ----- Original Message ----- 
> From: <th...@kodak.com>
> To: <ba...@xmlgraphics.apache.org>
> Cc: <ba...@xmlgraphics.apache.org>
> Sent: Wednesday, April 12, 2006 3:37 PM
> Subject: Re: Synchronizing JSVGCanvas - Again
> 
> 
> > Hi Andre,
> >
> > André Ávila <as...@nextech.com.br> wrote on 04/12/2006 02:08:14 PM:
> >
> > > I add my DrawOverlay to it, drawing
> > > only a standard rectangle. When I try to pan the image, the 
rectangle
> > goes
> > > off on its own. If you would spare a few minutes on this, you could
> > easily
> > > reproduce this behavior using the following code:
> > >
> > >  private class DrawOverlay implements Overlay {
> > >
> > >     Shape rect = new Rectangle2D.Double(200,200,100,100);
> > >
> > >     public void paint(Graphics g) {
> > >         AffineTransform at = getPaintingTransform();
> >
> >    This should be:
> >         AffineTransform at = getRenderingTransform();
> >
> >    The painting transform (if any) has actually already been applied 
for
> > you.
> >
> > > It's a bit strange, because it is essentially the same code as in
> > > TextSelectionManager.SelectionOverlay.paint(). What am I missing?
> >
> >    The TextSelectionManager uses getRenderingTransform not
> > getPaintingTransform().
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> > For additional commands, e-mail: 
batik-users-help@xmlgraphics.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by André Ávila <as...@nextech.com.br>.
Thanks, Thomas. It is perfect now.

I got a little confused with rendering and painting transform. For some
reason I played a lot with this code but never occured to me that I could be
applying the wrong transform. This is what happens after 14h work...

Anyway, I thought that pan interaction changed only the painting transform,
since is just repositioning a bitmap. So, what is the difference between
rendering and painting transform? Why do we need both?

----- Original Message ----- 
From: <th...@kodak.com>
To: <ba...@xmlgraphics.apache.org>
Cc: <ba...@xmlgraphics.apache.org>
Sent: Wednesday, April 12, 2006 3:37 PM
Subject: Re: Synchronizing JSVGCanvas - Again


> Hi Andre,
>
> André Ávila <as...@nextech.com.br> wrote on 04/12/2006 02:08:14 PM:
>
> > I add my DrawOverlay to it, drawing
> > only a standard rectangle. When I try to pan the image, the rectangle
> goes
> > off on its own. If you would spare a few minutes on this, you could
> easily
> > reproduce this behavior using the following code:
> >
> >  private class DrawOverlay implements Overlay {
> >
> >     Shape rect = new Rectangle2D.Double(200,200,100,100);
> >
> >     public void paint(Graphics g) {
> >         AffineTransform at = getPaintingTransform();
>
>    This should be:
>         AffineTransform at = getRenderingTransform();
>
>    The painting transform (if any) has actually already been applied for
> you.
>
> > It's a bit strange, because it is essentially the same code as in
> > TextSelectionManager.SelectionOverlay.paint(). What am I missing?
>
>    The TextSelectionManager uses getRenderingTransform not
> getPaintingTransform().
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by th...@kodak.com.
Hi Andre,

André Ávila <as...@nextech.com.br> wrote on 04/12/2006 02:08:14 PM:

> I add my DrawOverlay to it, drawing
> only a standard rectangle. When I try to pan the image, the rectangle 
goes
> off on its own. If you would spare a few minutes on this, you could 
easily
> reproduce this behavior using the following code:
> 
>  private class DrawOverlay implements Overlay {
> 
>     Shape rect = new Rectangle2D.Double(200,200,100,100);
> 
>     public void paint(Graphics g) {
>         AffineTransform at = getPaintingTransform();

   This should be:
        AffineTransform at = getRenderingTransform();

   The painting transform (if any) has actually already been applied for 
you.

> It's a bit strange, because it is essentially the same code as in
> TextSelectionManager.SelectionOverlay.paint(). What am I missing?

   The TextSelectionManager uses getRenderingTransform not 
getPaintingTransform().


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by André Ávila <as...@nextech.com.br>.
Hi Thomas,

> > They both could be holding SVG documents.
>
>    Ohh, the way you were talking it sounded like the top
> was empty and you had replaced it's paint method...

Sorry, I was not very clear about what I'm doing. This is the exact
situation I'm dealing with: the top canvas is empty, the bottom canvas has a
document, like you said. I need the top canvas to be an SVGCanvas because,
eventually, it might display documents as well.

But for the moment yes, we can assume the top canvas is empty and the user
will only draw Java2D shapes on it.

> > It seems a very good idea. I couldn't find much on using overlays in the
> > list, so maybe you can point me some further directions.
>
>    The Source code?  There really isn't much to know...

Yes, now I noticed... :)

>
> > I implemented the DrawOverlay class as an inner class of my SVG canvas]
> > private class DrawOverlay implements Overlay {
> >
> >   public void paint(Graphics g) {
> >    Graphics2D g2d = (Graphics2D)g;
> >    drawTool.drawShapes(g2d);    // Redraw all shapes
> >    repaint();    // Calls repaint on owner SVGCanvas
>
>     Don't call repaint this should lead to an infinite loop.
> If your list of shapes changes you will need to trigger a
> repaint of the canvas, it will then call your overlay to paint...

Right, that was dumb.

> > So here's my question: when is the overlay paint() method called? My
> first
> > guess was that it would be called every time the canvas repaint() (or
> > paint()?) was called, but I see this is not the case.
>
>    It is called whenever the canvas is painted - if the canvas has an
> offscreen image (i.e. it is rendering an SVG document), which from your
> earlier talk I'm guessing your top Canvas doesn't.  I would lean towards
> considering this behavior a bug (it's easy to fix, move the loop at the
> end
> of batik.swing.gvt.JGVTComponent.paintComponent outside the check if the
> image is null).

Ok, got it now. Looks like I'm almost there. Still, for some reason the
shapes are not transformed right.

Here's what I did to clear things a little bit. I have only one canvas now,
default subclass of JSVGCanvas (no overridden methods, just plain old
JSVGCanvas). It has a document rendered. I add my DrawOverlay to it, drawing
only a standard rectangle. When I try to pan the image, the rectangle goes
off on its own. If you would spare a few minutes on this, you could easily
reproduce this behavior using the following code:

 private class DrawOverlay implements Overlay {

    Shape rect = new Rectangle2D.Double(200,200,100,100);

    public void paint(Graphics g) {
        AffineTransform at = getPaintingTransform();

        Graphics2D g2d = (Graphics2D)g;

        Shape s = null;
        if (at != null) {
            s = at.createTransformedShape(rect);
        } else {
            s = rect;
        }

        g2d.setColor(Color.RED);
        g2d.draw(s);
}

It's a bit strange, because it is essentially the same code as in
TextSelectionManager.SelectionOverlay.paint(). What am I missing?


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by th...@kodak.com.
Hi Andre,

André Ávila <as...@nextech.com.br> wrote on 04/12/2006 09:48:01 AM:

> They both could be holding SVG documents.

   Ohh, the way you were talking it sounded like the top
was empty and you had replaced it's paint method...

> It seems a very good idea. I couldn't find much on using overlays in the
> list, so maybe you can point me some further directions.

   The Source code?  There really isn't much to know...

> I implemented the DrawOverlay class as an inner class of my SVG canvas]
> private class DrawOverlay implements Overlay {
> 
>   public void paint(Graphics g) {
>    Graphics2D g2d = (Graphics2D)g;
>    drawTool.drawShapes(g2d);    // Redraw all shapes
>    repaint();    // Calls repaint on owner SVGCanvas

    Don't call repaint this should lead to an infinite loop.
If your list of shapes changes you will need to trigger a
repaint of the canvas, it will then call your overlay to paint...

> So here's my question: when is the overlay paint() method called? My 
first
> guess was that it would be called every time the canvas repaint() (or
> paint()?) was called, but I see this is not the case.

   It is called whenever the canvas is painted - if the canvas has an
offscreen image (i.e. it is rendering an SVG document), which from your
earlier talk I'm guessing your top Canvas doesn't.  I would lean towards
considering this behavior a bug (it's easy to fix, move the loop at the 
end
of batik.swing.gvt.JGVTComponent.paintComponent outside the check if the
image is null).


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by André Ávila <as...@nextech.com.br>.
Hi Thomas,


> > I have two JSVGCanvas, one on top of the other. The bottom JSVGCanvas is
> used
> > for displaying an SVG document. The upper is used as an overlay for
> drawing.
> > They are both transparent.
>
>    Why is the upper one a JSVGCanvas? Just so you can get events or
> something?

Yes. The idea is to get the events in the upper canvas and propagate them to
the bottom canvas. In fact this is related to that previous thread I wrote
about synchronization. They both could be holding SVG documents.

> > Is there a better form of synchronizing the overlay? I'd like to reach
> the
> > same effect as the SelectionOverlay in TextSelectionManager.
>
>   Well the JSVGCanvas is happy to have multiple Overlays active, so you
> could
> easily make your shape drawing function a real Canvas Overlay.  Then You
> will
> more or less automatically pick up the rendering/painting transform
> changes.
> The signature of Overlay is just the one method 'void paint(Graphics g)'.
> As your overlay changes you will need to 'trigger' repaints of the canvas
> but
> it shouldn't be significantly different from what you already need to do.
>
>   All you need to do to register your overlay is:
>         canvas.getOverlays().add(myOverlay);

It seems a very good idea. I couldn't find much on using overlays in the
list, so maybe you can point me some further directions.

I implemented the DrawOverlay class as an inner class of my SVG canvas and
added it to the canvas as you showed.:

private class DrawOverlay implements Overlay {

  public void paint(Graphics g) {
   Graphics2D g2d = (Graphics2D)g;
   drawTool.drawShapes(g2d);    // Redraw all shapes
   repaint();    // Calls repaint on owner SVGCanvas
}

So here's my question: when is the overlay paint() method called? My first
guess was that it would be called every time the canvas repaint() (or
paint()?) was called, but I see this is not the case.


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Synchronizing JSVGCanvas - Again

Posted by th...@kodak.com.
Hi André,

André Ávila <as...@nextech.com.br> wrote on 04/11/2006 05:28:01 PM:

> I have two JSVGCanvas, one on top of the other. The bottom JSVGCanvas is 
used 
> for displaying an SVG document. The upper is used as an overlay for 
drawing. 
> They are both transparent.

   Why is the upper one a JSVGCanvas? Just so you can get events or 
something?

> Since the overlay canvas just has a bunch of Shapes all I have to do is 
> apply the same transform to its graphics context to make the Shapes 
> move or zoom with the SVG canvas. Below is the paint() method of the 
> overlay canvas.

> public void paint(Graphics g) {

> However, the final result does not look good: it always looks like the 
overlay
> canvas is a few milliseconds behind

> Is there a better form of synchronizing the overlay? I'd like to reach 
the 
> same effect as the SelectionOverlay in TextSelectionManager.

  Well the JSVGCanvas is happy to have multiple Overlays active, so you 
could
easily make your shape drawing function a real Canvas Overlay.  Then You 
will
more or less automatically pick up the rendering/painting transform 
changes.
The signature of Overlay is just the one method 'void paint(Graphics g)'.
As your overlay changes you will need to 'trigger' repaints of the canvas 
but
it shouldn't be significantly different from what you already need to do.

  All you need to do to register your overlay is:
        canvas.getOverlays().add(myOverlay);


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org