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 Heinz Doerr <he...@ecoms.de> on 2009/06/08 12:20:46 UTC

JSVGCanvas : Auto-Fit To window size

Hi, I'm quite new to Batik, I've also tried to find an answer on the
web, but didn't
find anything helpful. Didn't find any search functionality on the mail
archive either.

I'm using the JSVGCanvas , very nice, but I need to scale the displayed SVG
image to fit the window size of the canvas.
So no scrolling, rotation or panning needed.
This should work for any SVG (with or w/o a ViewBox) - changing the svg
file itself it not an option.
The aspect ratio should always be unchanged.
Nice, would be to have an option to either scale down only or to allow
scale up and down.

Because I didn't found any 'scale-to-fit' hints, I was thinking if it
would be better to use
the BufferedImageTranscoder and convert the svg to an image. The transcoder
has the scale-to-fit build in (very nice - works with any SVG, keeps the
aspect ratio),
but then I got problems loading some svg's. I'm not sure how to get
javascript, onLoad,
references to elements, and security under control. Having animation
with the Canvas solution
would also be a nice to have.

So I think I'm looking for something like an Action AutoFit for the
canvas, and this action
automatically triggered (at the right time?).

Please help ....

Greetings
Heinz



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


Re: JSVGCanvas : Auto-Fit To window size

Posted by Helder Magalhães <he...@gmail.com>.
Hi Heinz,


> I played around - w/o really understanding what I do - and
> found - in a very short time - a solution which surprisingly
> works quite good. Amazing well. Code, see end of this message.

Thanks for sharing your solution. :-)


> But I have a few questions:
> =====================
[...]
> * I've an assert
>         assert fragIdent == null;
>     which never triggered in my tests, for what is this fragIdent ???

In this scope, probably it stands for "fragment identifier" [1]. ;-)


Regards,
 Helder


[1] http://www.w3.org/TR/SVG/linking.html#SVGFragmentIdentifiers

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


Re: JSVGCanvas : Auto-Fit To window size

Posted by Heinz Doerr <he...@ecoms.de>.
Hi Thomas,

    thanks a lot for your help. I changed and tested my class
using your proposed getBBox() method. Works great for
all SVG files I have on my hard drive.
Looks more robust now, yes feels like 98%.  :-)

    The class below can be used instead of it's base class,
extends it's base class so that - if setAutoFitToCanvas(true) -
it will automatically center/resize the svg on the canvas.
It still supports
    * canvas size changes (with automatically resizing the svg)
    * the keyboard actions
    * as well as svg's with animation.
         (changes of the documents size by a script
            may result in strange results, but that's
           true for JSVGCanvas as well)

   Right now fragIdent != null IS NOT SUPPORTED !!!
Mainly because I don't understand this parameter AND I didn't
found a single test case to understand and test it.

Greetings Heinz



public class SvgCanvasXx extends JSVGCanvas {
   
    protected int xBorder= 8;
    protected int yBorder= 8;
    protected boolean autoFitToCanvas;
    protected boolean stopProcessingOnDispose;
   

    public SvgCanvasXx() {
    }

    public SvgCanvasXx(SVGUserAgent ua, boolean eventsEnabled, boolean
selectableText) {
        super(ua, eventsEnabled, selectableText);
    }
   
    public boolean isAutoFitToCanvas() {
        return autoFitToCanvas;
    }

    public void setAutoFitToCanvas(boolean autoFit) {
        this.autoFitToCanvas= autoFit;
        if (autoFit)
            setRecenterOnResize(true);
    }
   
    public boolean isStopProcessingOnDispose() {
        return stopProcessingOnDispose;
    }

    public void setStopProcessingOnDispose(boolean
stopProcessingOnDispose) {
        this.stopProcessingOnDispose= stopProcessingOnDispose;
    }

    /** note the border will be ignored if canvas width/height <= 4 *
borderX/Y **/
    public void setInnerBorderWidth(int borderX, int borderY) {
        this.xBorder= borderX;
        this.yBorder= borderY;
    }
   
    @Override
    public void dispose() {
        if (stopProcessingOnDispose)
            stopProcessing();
        super.dispose();
    }
   
    @Override
    protected void installKeyboardActions() {
        super.installKeyboardActions();
        InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
        KeyStroke key;
        // .....
    }

    /**
     * overwrites calculateViewingTransform to allow autoFitToCanvas
behaviour,
     * if autoFitToCanvas is not set it will use the base's class method.
     *
     * Right now fragIdent != null IS NOT SUPPORTED !!!
     */
    @Override
    protected AffineTransform calculateViewingTransform(String
fragIdent, SVGSVGElement svgElt) {
        assert fragIdent == null; // don't understand this parameter,
have not found a simple test case yet
        if (!autoFitToCanvas || fragIdent != null)
            return super.calculateViewingTransform(fragIdent, svgElt);
        // canvas size / additional border
        Dimension d = getSize();
        int xb= 0, yb= 0;
        if (d.width  < 1) d.width  = 1;
        if (d.height < 1) d.height = 1;
        if (d.width > 4 * xBorder) // if canvas is large enough add border
            d.width-= 2 * (xb= xBorder);
        if (d.height > 4 * yBorder) // if canvas is large enough add border
            d.height-= 2 * (yb= yBorder);
        //
        AffineTransform tf;
       //
        String viewBox= svgElt.getAttributeNS(null,
ViewBox.SVG_VIEW_BOX_ATTRIBUTE);
        if (viewBox.length() == 0) {
            // no viewbox specified, make an own one
            float[] vb= calculateDefaultViewbox(fragIdent, svgElt);
            tf= ViewBox.getPreserveAspectRatioTransform(
                    vb,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID, true, d.width,
d.height);
        } else {
            String aspectRatio= svgElt.getAttributeNS(null,
ViewBox.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE);
            if (aspectRatio.length() > 0)
                tf= ViewBox.getPreserveAspectRatioTransform(svgElt,
viewBox, aspectRatio, d.width, d.height, bridgeContext);
            else {
                float[] vb= ViewBox.parseViewBoxAttribute(svgElt,
viewBox, bridgeContext);
                tf= ViewBox.getPreserveAspectRatioTransform(
                        vb,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX, true, d.width,
d.height);
            }
        }
        if (xb > 0 || yb > 0) { // center image
            AffineTransform tf2=
AffineTransform.getTranslateInstance(xb, yb);
            tf2.concatenate(tf);
            tf= tf2;
        }
        return tf;
    }
   
    protected float[] calculateDefaultViewbox(String fragIdent,
SVGSVGElement svgElt) {
        float[] vb= new float[4];
         SVGRect rc= svgElt.getBBox();
        vb[0]= rc.getX();
        vb[1]= rc.getY();
        vb[2]= rc.getWidth();
        vb[3]= rc.getHeight();
        return vb;
    }
   
}



thomas.deweese@kodak.com schrieb:
>
> Hi Heinz,
>
> Heinz Doerr <he...@ecoms.de> wrote on 06/09/2009 04:42:49 PM:
>
> > But for a doc w/o a ViewBox specified I need the "size of the
> > document".
>
>
> > But I have a few questions:
> > =====================
> > * Overall, how far away is my "90%" solution from 100% ???
> >     As I stated - I'm not sure what I'm doing here
>
>    You are close.
>
> > * I'm calling svgElt.getWidth() and getHeight(),
> >     Are those values always defined?
> >     Are those values always pixel based?
>
>      No, and no, although the majority are pixels (well
> unitless which is userspace units).
>
> > * to get the origin of the doc I call  svgElt.getX() and getY(),
> >     Is this correct?
> >     Are those values always pixel based?
>
>     No, and no, those are supposed to be ignored on the
> root SVG element.
>
> > With some help I would surely try to contribute a "98%" solution
> > to the community.
>
>    The best way to get the last 8% would be to move to
> using 'getBBox()' on the root SVG Element.  This will
> tell you the actual size of the geometry in the document.
>
> >
> > thomas.deweese@kodak.com schrieb:
> >
> > Hi Heinz Doerr,
> >
> > Heinz Doerr <he...@ecoms.de> wrote on 06/08/2009 06:20:46 AM:
> >
> > > I'm using the JSVGCanvas , very nice, but I need to scale the
> displayed SVG
> > > image to fit the window size of the canvas.
> > > So no scrolling, rotation or panning needed.
> > > This should work for any SVG (with or w/o a ViewBox) - changing
> the svg
> > > file itself it not an option.
> > > The aspect ratio should always be unchanged.
> > > Nice, would be to have an option to either scale down only or to allow
> > > scale up and down.
> >
> >    That is quite a list of requirements.
> >
> > > Because I didn't found any 'scale-to-fit' hints, I was thinking if it
> > > would be better to use
> > > the BufferedImageTranscoder and convert the svg to an image. The
> transcoder
> > > has the scale-to-fit build in (very nice - works with any SVG,
> keeps the
> > > aspect ratio), but then I got problems loading some svg's. I'm not
> sure
> > > how to get javascript, onLoad, references to elements, and
> security under
> > > control. Having animation with the Canvas solution would also be a
> > nice to have.
> >
> >    There are options to run onload scripts before the rendering.
> >
> > > So I think I'm looking for something like an Action AutoFit for the
> > > canvas, and this action automatically triggered (at the right time?).
> >
> >    What I think will work best is for you to override
> > 'JSVGComponent.calculateViewingTransform' to implement your
> > desired scale to fit algorythem.  If you get it working you
> > might consider contributing it back so others could make use
> > of it. 


Re: JSVGCanvas : Auto-Fit To window size

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

Heinz Doerr <he...@ecoms.de> wrote on 06/09/2009 04:42:49 PM:

> But for a doc w/o a ViewBox specified I need the "size of the
> document". 


> But I have a few questions:
> =====================
> * Overall, how far away is my "90%" solution from 100% ???
>     As I stated - I'm not sure what I'm doing here

   You are close.

> * I'm calling svgElt.getWidth() and getHeight(),
>     Are those values always defined?
>     Are those values always pixel based?

     No, and no, although the majority are pixels (well
unitless which is userspace units).

> * to get the origin of the doc I call  svgElt.getX() and getY(),
>     Is this correct?
>     Are those values always pixel based?

    No, and no, those are supposed to be ignored on the
root SVG element.

> With some help I would surely try to contribute a "98%" solution
> to the community.

   The best way to get the last 8% would be to move to
using 'getBBox()' on the root SVG Element.  This will
tell you the actual size of the geometry in the document.

> 
> thomas.deweese@kodak.com schrieb: 
> 
> Hi Heinz Doerr,
> 
> Heinz Doerr <he...@ecoms.de> wrote on 06/08/2009 06:20:46 AM:
> 
> > I'm using the JSVGCanvas , very nice, but I need to scale the 
displayed SVG
> > image to fit the window size of the canvas.
> > So no scrolling, rotation or panning needed.
> > This should work for any SVG (with or w/o a ViewBox) - changing the 
svg
> > file itself it not an option.
> > The aspect ratio should always be unchanged.
> > Nice, would be to have an option to either scale down only or to allow
> > scale up and down.
> 
>    That is quite a list of requirements. 
> 
> > Because I didn't found any 'scale-to-fit' hints, I was thinking if it
> > would be better to use
> > the BufferedImageTranscoder and convert the svg to an image. The 
transcoder
> > has the scale-to-fit build in (very nice - works with any SVG, keeps 
the
> > aspect ratio), but then I got problems loading some svg's. I'm not 
sure 
> > how to get javascript, onLoad, references to elements, and security 
under 
> > control. Having animation with the Canvas solution would also be a
> nice to have.
> 
>    There are options to run onload scripts before the rendering. 
> 
> > So I think I'm looking for something like an Action AutoFit for the
> > canvas, and this action automatically triggered (at the right time?).
> 
>    What I think will work best is for you to override 
> 'JSVGComponent.calculateViewingTransform' to implement your 
> desired scale to fit algorythem.  If you get it working you 
> might consider contributing it back so others could make use 
> of it. 

Re: JSVGCanvas : Auto-Fit To window size

Posted by Heinz Doerr <he...@ecoms.de>.
Hi Thomas,

>>> What I think will work best is for you to override
>>> 'JSVGComponent.calculateViewingTransform' to implement your

Ok, thanks alot for the very good hint -
helped me already to understand a " little bit".
Actually, if there is a ViewBox specified in the svg doc it's simple.
But for a doc w/o a ViewBox specified I need the "size of the
document".

I played around - w/o really understanding what I do - and
found - in a very short time - a solution which surprisingly
works quite good. Amazing well. Code, see end of this message.

I tested it with about 100 of examples from the http://www.openclipart.org/,
my part worked as expected.

With the samples in the batik folders it worked as expected (i think)
with all but:
* the cursor svg's  (wrong origin, scale?)
* the svg which changes the viewport in the onClick handler (but that's ok)

But I have a few questions:
=====================
* Overall, how far away is my "90%" solution from 100% ???
    As I stated - I'm not sure what I'm doing here
* I've an assert
        assert fragIdent == null;
    which never triggered in my tests, for what is this fragIdent ???
* I'm calling svgElt.getWidth() and getHeight(),
    Are those values always defined?
    Are those values always pixel based?
* to get the origin of the doc I call  svgElt.getX() and getY(),
    Is this correct?
    Are those values always pixel based?

With some help I would surely try to contribute a "98%" solution
to the community.

Greetings Heinz

Here my code:  !!! surely not 100% correct !!!!

Note: as of now
if autoFitToCanvas is true,
it basically disables the zoom actions

public class SvgCanvasXx extends JSVGCanvas {
   
    protected int xBorder= 8;
    protected int yBorder= 8;
    protected boolean autoFitToCanvas;
   

    public SvgCanvasXx() {
    }

    public SvgCanvasXx(SVGUserAgent ua, boolean eventsEnabled, boolean
selectableText) {
        super(ua, eventsEnabled, selectableText);
    }
   
    public void setAutoFitToCanvas(boolean autoFit) {
        this.autoFitToCanvas= autoFit;
    }
   
    @Override
    protected AffineTransform calculateViewingTransform(String
fragIdent, SVGSVGElement svgElt) {
        assert fragIdent == null;
        if (!autoFitToCanvas)
            return super.calculateViewingTransform(fragIdent, svgElt);
        // canvas size / additional border
        Dimension d = getSize();
        int xb= 0, yb= 0;
        if (d.width  < 1) d.width  = 1;
        if (d.height < 1) d.height = 1;
        if (d.width > 5 * xBorder) // if canvas is large enough add border
            d.width-= 2 * (xb= xBorder);
        if (d.height > 5 * yBorder) // if canvas is large enough add border
            d.height-= 2 * (yb= yBorder);
        //
        AffineTransform tf;
       //
        String viewBox= svgElt.getAttributeNS(null,
ViewBox.SVG_VIEW_BOX_ATTRIBUTE);
        if (viewBox.length() == 0) {
            // no viewbox specified, make an own one
            float[] vb= calculateDefaultViewbox(fragIdent, svgElt);
            tf= ViewBox.getPreserveAspectRatioTransform(
                    vb,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX, true, d.width,
d.height);
        } else {
            String aspectRatio= svgElt.getAttributeNS(null,
ViewBox.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE);
            if (aspectRatio.length() > 0)
                tf= ViewBox.getPreserveAspectRatioTransform(svgElt,
viewBox, aspectRatio, d.width, d.height, bridgeContext);
            else {
                float[] vb= ViewBox.parseViewBoxAttribute(svgElt,
viewBox, bridgeContext);
                tf= ViewBox.getPreserveAspectRatioTransform(
                        vb,
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX, true, d.width,
d.height);
            }
        }
        if (xb > 0 || yb > 0) { // center image
            AffineTransform tf2=
AffineTransform.getTranslateInstance(xb, yb);
            tf2.concatenate(tf);
            tf= tf2;
        }
        return tf;
    }
   
    protected float[] calculateDefaultViewbox(String fragIdent,
SVGSVGElement svgElt) {
        float[] vb= new float[4];
        // get doc's origin
        SVGAnimatedLength alx= svgElt.getX(); // todo: is this correct ???
        SVGLength x= alx != null ? alx.getBaseVal() : null;
        SVGAnimatedLength aly= svgElt.getY(); // todo: is this correct ???
        SVGLength y= aly != null ? aly.getBaseVal() : null;
        // get docs dimensions
        SVGAnimatedLength w= svgElt.getWidth();
        SVGLength bw= w != null ? w.getBaseVal() : null;
         SVGAnimatedLength h= svgElt.getHeight();
        SVGLength bh= h != null ?  h.getBaseVal() : null;
        //
        vb[0]= x != null ? x.getValue() : 0;
        vb[1]= y != null ? y.getValue() : 0;
        vb[2]= (bw != null ? bw.getValue() : 100); // 100 random value
        vb[3]= (bh != null ? bh.getValue() : 100);
        return vb;
    }

}




thomas.deweese@kodak.com schrieb:
>
> Hi Heinz Doerr,
>
> Heinz Doerr <he...@ecoms.de> wrote on 06/08/2009 06:20:46 AM:
>
> > I'm using the JSVGCanvas , very nice, but I need to scale the
> displayed SVG
> > image to fit the window size of the canvas.
> > So no scrolling, rotation or panning needed.
> > This should work for any SVG (with or w/o a ViewBox) - changing the svg
> > file itself it not an option.
> > The aspect ratio should always be unchanged.
> > Nice, would be to have an option to either scale down only or to allow
> > scale up and down.
>
>    That is quite a list of requirements.
>
> > Because I didn't found any 'scale-to-fit' hints, I was thinking if it
> > would be better to use
> > the BufferedImageTranscoder and convert the svg to an image. The
> transcoder
> > has the scale-to-fit build in (very nice - works with any SVG, keeps the
> > aspect ratio), but then I got problems loading some svg's. I'm not sure
> > how to get javascript, onLoad, references to elements, and security
> under
> > control. Having animation with the Canvas solution would also be a
> nice to have.
>
>    There are options to run onload scripts before the rendering.
>
> > So I think I'm looking for something like an Action AutoFit for the
> > canvas, and this action automatically triggered (at the right time?).
>
>    What I think will work best is for you to override
> 'JSVGComponent.calculateViewingTransform' to implement your
> desired scale to fit algorythem.  If you get it working you
> might consider contributing it back so others could make use
> of it.


Re: JSVGCanvas : Auto-Fit To window size

Posted by th...@kodak.com.
Hi Heinz Doerr,

Heinz Doerr <he...@ecoms.de> wrote on 06/08/2009 06:20:46 AM:

> I'm using the JSVGCanvas , very nice, but I need to scale the displayed 
SVG
> image to fit the window size of the canvas.
> So no scrolling, rotation or panning needed.
> This should work for any SVG (with or w/o a ViewBox) - changing the svg
> file itself it not an option.
> The aspect ratio should always be unchanged.
> Nice, would be to have an option to either scale down only or to allow
> scale up and down.

   That is quite a list of requirements.

> Because I didn't found any 'scale-to-fit' hints, I was thinking if it
> would be better to use
> the BufferedImageTranscoder and convert the svg to an image. The 
transcoder
> has the scale-to-fit build in (very nice - works with any SVG, keeps the
> aspect ratio), but then I got problems loading some svg's. I'm not sure 
> how to get javascript, onLoad, references to elements, and security 
under 
> control. Having animation with the Canvas solution would also be a nice 
to have.

   There are options to run onload scripts before the rendering.

> So I think I'm looking for something like an Action AutoFit for the
> canvas, and this action automatically triggered (at the right time?).

   What I think will work best is for you to override 
'JSVGComponent.calculateViewingTransform' to implement your
desired scale to fit algorythem.  If you get it working you
might consider contributing it back so others could make use 
of it.