views:

4057

answers:

7
+6  Q: 

Using SVG in GWT

I was wondering if it is possible to include SVG content inside a panel (or whatever would work in GWT), be able to add more to the SVG (like add a circle or a curve) programmatically , and handle mouse events (would this be in SVG or GWT?). I've tried creating an HTML object adding something along the lines of:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <circle cx="50" cy="50" r="30" /> </svg>

That didn't work (nothing visible in output) but I'm not sure if it was because I did it wrong or it's not allowed.

I was able to do a simple example in GWT with Google Visualization's LineChart but I'd like to move away from Google Visualization and be able to generate the SVG myself and customize it further. I've looked around and many resources points to using Canvas but I'm not sure if that's the best route yet.

I'm also a bit baffled about the example here. I tried a simple copy-paste of it to try locally and it didn't seem to work at all. I was however able to get another sample working with just HTM (embed with src pointing to SVG file) L + separate SVG file but I haven't been able to access it using GWT using RootPanel.get(...).

EDIT: I've read about SVG not working with Hosted Browser and compiling it does work but I am uncertain how to refer to the SVG (which I have placed into the HTML via ). If I can access it then presumably I can add to its innerHTML. I've tried in RootPanel.get("hi").getElement().setInnerHTML("...") but that doesn't seem to work or did I mess up? I guess the goal is to be able to manipulate a SVG file which I linked somehow (whether in GWT or in HTML) and be able to modify it based on user's input.

2nd EDIT So far, I've been programming functionality inside of the actual SVG file. In our setup, our SVG is an embedded object and we passed 'document' to the embedded SVG. Passing information from an embed object to and from HTML is quite doable since the HTML has access to our SVG functions and the SVG has access to the 'document'.

There are more transparent ways of doing so (Rapahel) where FireBug could see the SVG directly which is nice but now not quite necessary. Thus far, I don't think any of the solutions I've looked at were IFrames but I could be wrong. A little warning, SVG can be pretty slow sometimes.

I would say my issue is solved (sort of?) but I'm not using Raphael, jQuery, nor GWT at the moment but the method I described in my answer should still work if I want to use GWT.

+2  A: 

You might stuble about the html vs xhtml problem: inline SVG needs to be interpreted as XML/XHTML, but at least for me, I cannot persuade GWT to live with applicaton/xhtml+xml as a content type. For the local test you wonder about: try to save the file as .xhtml and load it into Firefox - then it works, because FF in this case interprets it as XHTML.

See http://wiki.svg.org/Inline_SVG for background information.

If you find a solution to the problem, please post. Regards, Axel

I'll definitely take a closer look at the inline SVG bit as that may be the best way to do it, otherwise I'd maybe have to use JavaScript to grab the SVG for GWT. I'll post back when I get some results!
nevets1219
+3  A: 

After playing around a bit, I've been most successful with using Raphaël (which handles cross-browser compatibility) though I suspect anything along those lines would work just fine. Basically I do the following in JavaScript:

var r = Raphael("someID", WND_WIDTH, WND_HEIGHT);
// additional configuration and setup if needed....

Then I would do the following in GWT:

public native JavaScriptObject getRaphael() /*-{
  return $wnd.r;
}-*/;

// I now have access to the JavaScript object and could do the following:

public native void drawCircle(JavaScriptObject obj, int x, int y, int r) /*-{
  obj.circle(x, y, r);
}-*/;

I've also been reading around and it seems that porting Raphaël into GWT (this article is a good read) will not only increase performance (as per some post I read on Google Groups but can't find at the moment - they mentioned the compiler does quite a bit of work) but also facilitate coding & debugging.

So I accomplished my goal of being able to manipulate the SVG directly (somewhat until I port Raphaël into Java or at least create wrappers). I have yet to look seriously into the Google Visualization API but I suspect it might work just as well but I'm not sure if it is robust enough for my needs.

An important thing I believe I was missing as stated on Raphaël's site was the following:

This means every graphical object you create is also a DOM object, so you can attach JavaScript event handlers or modify them later.

nevets1219
if you are porting raphael into gwt, i would be interested to know!
Chii
I'm not porting it but at the time, it was a consideration.
nevets1219
I am in the process of porting it to gwt. Have done 80% of the work and now I am in the process of publishing it to github. Will post when available.
Sten Roger
Sounds good, I'm sure many people will be interested in seeing this. Using SVG as I have found out is pretty CPU intensive - at least for what I did.
nevets1219
Hey Sten, any success with publishing those JSO wrappers?
skrat
+1  A: 

If you cannot see your SVG it may be because your browser see your document as an HTML file but NOT as an XHTML file. Try to change the extension of your file (.xhtml), check your html is well formed, add an html 'meta' tag etc..

FYI , There is also a SVG module for GWT: http://gwt-widget.sourceforge.net/

Pierre

Pierre
nevets1219
A: 

Be warned that SVG will not work in current GWT Shell (Hosted mode) up to 1.6 inclusive, because:

1) on windows, it uses IE component

2) on Linux, it uses Firefox 1.0 or equal mozilla runtime, which has no support for SVG.

Compiled code works fine in non-IE browsers.

Also, it works regardless of HTML/XHTML in browsers, because in GWT you use createElementNS (you can code method yourself using JSNI). Also, your SVG tag may need width/height attributes (see SVG spec).

san
A: 

Interesting!

I've tried to use Raphael through GWT/Java code but I can't seem to be able to use your trick.

I have the following block in my HTML page :

<script  type="text/javascript" language="javascript" ><br/>
     window.onload=function(){
     var rr = Raphael(20,20, 200,200);
     rr.circle(50,40,30);
     }
</script>

When I compile/browse the page in Firefox, I get my circle in my page, no problem.

Then I add the following native java to my module entrypoint method and call it :

 private native JavaScriptObject returnRaphael() /*-{
         return $wnd.rr;
        }-*/;

Debugging shows that the returned object is always null...

Plus, I don't understand why I could not simply do the following in my Java code:

public native void createRaphael()/*-{
    Raphael("some_div", 200,200);
}-*/;

GWT keeps telling me that Raphael does not exist, though, as I see through firebug, the library is perfectly included. This does not work either :

public native void createRaphael()/*-{
    $wnd.Raphael("some_div", 200,200);
}-*/;

Surprinsingly, I manage to access draw2d (openJacob draw2d) classes and functions with that $wnd but not my Raphael objects... There must be something I did not get...

I think in your first case, the variable 'rr' is local to that function, declare it globally and it should be fine (I hope). You could definitely declare the Raphael object within GWT, but I believe you'll need to tell GWT where the JS library is located. I don't believe including it within the HTML file will be enough but perhaps someone with more experience on it could tell you for sure.
nevets1219
I've found that the GWTShell does not support SVG and thus fails at loading the module if I invoke Raphael (through JSNI) in onModuleLoad(). Raphael executed through a callback or even a DeferredCommand does nothing in the GWTShell, but works fine after a compile/browse in Firefox. Thanks!
A: 

I don't entirely understand why, but the createElementNS JavaScript method allows you to create and correctly format xhtml within html.

Because there is no equivalent in explorer, GWT does not implement createElementNS, but you can with a quick native method :

private static native Element createElementNS(final String ns, 
        final String name)/*-{
    return document.createElementNS(ns, name);`  
}-*/;

it makes sense to put this in a SVGPanel class

import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ComplexPanel;

public class SVGPanel extends ComplexPanel{

    private static final String SVG_NAMESPACE = "http://www.w3.org/2000/svg";

    public SVGPanel() {
        setElement(createElementNS(SVG_NAMESPACE, "svg"));
        showcaseSVG(); //Demonstrate that SVG works! Inexplicably!
    }

    private void showcaseSVG(){
        Element svgElement = createElementNS(SVG_NAMEPSACE, "circle");
        svgElement.setAttribute("cx", "50");
        svgElement.setAttribute("cy", "50");
        svgElement.setAttribute("r", "30");
        getElement().appendChild(svgElement);
    }
}

This should produce some simple SVG when added to your program. Congratulations! You are now sticking it to the xhtml man.

Jared Garst
+1  A: 

We just open-sourced a GWT widget that allows you to integrate GWT with Raphael: http://code.google.com/p/raphaelgwt/

This widget was originally created for Hydro4GE and was mentioned in an article on the official GWT Blog.

Tim Speicher