Here is a starter to use Open Flash Charts and Wicket:

check: http://teethgrinder.co.uk/open-flash-chart-2/ http://code.google.com/p/ofcj/ http://code.google.com/p/swfobject/

We need a component for loading SWF objects (this is not specific to Open Flash Charts, it can be used for any swf object).

package com.mycompany.ofc2;

import java.util.Map;
import java.util.HashMap;

import org.apache.wicket.Component;
import org.apache.wicket.behavior.AbstractBehavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.resources.CompressedResourceReference;

/**
 *
 */
public class SWFObject extends AbstractBehavior implements IHeaderContributor {

  private static final CompressedResourceReference SWFOBJECT_JS =
      new CompressedResourceReference(SWFObject.class, "swfobject-2.1.js");

  private static final long serialVersionUID = 1L;

  private Map<String, String> parameters = new HashMap<String, String>();

  private Map<String, String> attributes = new HashMap<String, String>();

  private String version;
  private String flashUrl;
  private String width;
  private String height;
  private Component component;

  @Override
	public void bind(Component component) {
		this.component = component;
		component.setOutputMarkupId(true);
  }

  public void renderHead(IHeaderResponse response) {
    response.renderJavascriptReference(SWFOBJECT_JS);

    final String id = component.getMarkupId();
    String parObj = buildDataObject(getParameters());
    String attObj = buildDataObject(getAttributes());

    // embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj)

    String js = String.format("swfobject.embedSWF('%s','%s', '%s', '%s', '%s', '%s', %s, %s );",
        flashUrl, id, width, height, version, "expressInstall.swf", parObj, attObj);
    
    if(AjaxRequestTarget.get() != null) {
         AjaxRequestTarget.get().appendJavascript(js); //To enable js is rendered when loaded via ajax
    } 
    else {
         response.renderJavascript(js, null);
    }
  }

  /**
   * Construct.
   * <p/>
   * version can be a string in the format of 'majorVersion.minorVersion.revision'.
   * An example would be: "6.0.65". Or you can just require the major version, such as "6".
   *
   * @param flashUrl        The url of your swf file.
   * @param width           width of swf
   * @param height          height of movie
   * @param version         Flash version to support
   */
  public SWFObject(final String flashUrl, final int width, final int height, final String version) {
    this(flashUrl, String.valueOf(width), String.valueOf(height), version);
  }

  /**
   * Construct.
   * @param flashUrl        URL to load up for swf
   * @param width           width of swf
   * @param height          height of movie
   * @param version         Flash version to support
   */
  public SWFObject(final String flashUrl, final String width, final String height, final String version) {
    if (flashUrl == null) {
      throw new IllegalArgumentException("Argument [flashUrl] cannot be null");
    }
    this.flashUrl = flashUrl;
    this.width = width;
    this.height = height;
    this.version = version;
  }

   private String buildDataObject(Map<String,String> data) {
    final String quote = "'";
    final String comma=",";
    if (data != null && !data.isEmpty()) {
      StringBuilder result = new StringBuilder();
      result.append("{");
      for (Map.Entry<String, String> e : getParameters().entrySet()) {
        result.append(quote).append(e.getKey()).append(quote + ":" + quote).append(e.getValue()).append(quote).append(comma);
      }
      result.deleteCharAt(result.length() - 1);
      result.append("}");
      return result.toString();
    }
    return "{}";
  }

  @Override
  public void onComponentTag(final Component component, final ComponentTag tag) {
  }

  protected Map<String, String> getParameters() {
    return parameters;
  }

  public void addParameter(String name, String value) {
    parameters.put(name, value);
  }

  protected Map<String, String> getAttributes() {
    return attributes;
  }

  public void addAttribute(String name, String value) {
    attributes.put(name, value);
  }

}

Useful Information

Make sure that the referenced javascript file swfobject-2.1.js is on the classpath.
If you use maven, you can save the file as src/main/resources/com/mycompany/ofc2/swfobject-2.1.js

Now the OpenFlashChart component itself:

package com.mycompany.ofc2;

import org.apache.wicket.IResourceListener;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.markup.html.WebResource;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.protocol.http.RequestUtils;
import org.apache.wicket.util.resource.AbstractStringResourceStream;
import org.apache.wicket.util.resource.IResourceStream;

import ofc4j.model.Chart;

/**
 * Panel for showing a Flash Chart
 */
public class OpenFlashChart extends Panel implements IResourceListener {

  static final ResourceReference SWF_RESOURCE = new ResourceReference(OpenFlashChart.class, "open-flash-chart.swf" );

  final WebResource jsonResource;
  final SWFObject swf;

  public OpenFlashChart(String id, final String width, final String height, final Chart chart) {
    this(id, width, height, new Model<String>(chart.toString()));
  }

  public OpenFlashChart(String id, final int width, final int height, final Chart chart) {
    this(id, String.valueOf(width), String.valueOf(height), new Model<String>(chart.toString()));
  }

  public OpenFlashChart(String id, final int width, final int height, IModel<String> jsonModel) {
    this(id, String.valueOf(width), String.valueOf(height), jsonModel);
  }

  public OpenFlashChart(String id, final String width, final String height, final IModel<String> jsonModel) {
    super(id);

    final IResourceStream json = new AbstractStringResourceStream("text/plain") {
      @Override
      public String getString() {
        return jsonModel.getObject();
      }
    };

    jsonResource = new WebResource() {
      @Override
      public IResourceStream getResourceStream() {
        return json;
      }
    };
    jsonResource.setCacheable(false);

    String swfURL = RequestUtils.toAbsolutePath( urlFor(SWF_RESOURCE).toString() );
    add(swf = new SWFObject( swfURL, width, height, "9.0.0"));
  }


  private String getUrlForJson() {
    CharSequence dataPath = RequestCycle.get().urlFor(OpenFlashChart.this, IResourceListener.INTERFACE);
    return RequestUtils.toAbsolutePath( dataPath.toString() );
  }

  @Override
  protected void onBeforeRender() {
    swf.addParameter("data-file", getUrlForJson());
    super.onBeforeRender();

  }

  /**
   * Actually handle the request
   */
  public void onResourceRequested() {
    jsonResource.onResourceRequested();
  }
}

Useful Information

Make sure to have open-flash-chart.swf on your classpath.
You can save the file as src/main/resources/com/mycompany/ofc2/open-flash-chart.swf

The accompanying html is rather short (smile)

<wicket:panel>
</wicket:panel>

Using the component is easy. You need to generate the json that defines your chart.

  • You can generate it yourself, and pass the json to the OpenFlashChart constructor that takes an Model<String>
  • or you can use http://code.google.com/p/ofcj/ and use the constructor that takes an ofc4j.model.Chart

Example:

package com.mycompany;

import org.apache.wicket.model.Model;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.WebPage;
import com.mycompany.ofc2.OpenFlashChart;
import ofc4j.model.elements.BarChart;
import ofc4j.model.Chart;

/**
 * Homepage
 */
public class HomePage extends WebPage {

  private static final long serialVersionUID = 1L;

  public HomePage() {

    add(new Label("message", "If you see this message wicket is properly configured and running"));

    // a) json hard-coded
    String json = "{\"elements\":[{\"type\":\"bar\",\"values\":[1,2,3,4,5,6,7,8,9]}],\"title\":{\"text\":\"Tue Oct 14 2008\"}}";

    add(new OpenFlashChart("chart1", 200, 300, new Model<String>(json)));

    // b) use http://code.google.com/p/ofcj/ 
    BarChart bar1 = new BarChart(BarChart.Style.GLASS);
    bar1.setColour("#007FFF");
    bar1.setTooltip("Beers:<br>Value:#val#");
    bar1.addValues(1,5,8,3,0,2);
    bar1.setText("Beers consumed");
    bar1.setAlpha(0.1f);

    BarChart bar2 = new BarChart(BarChart.Style.GLASS);
    bar2.setColour("#802A2A");
    bar2.setTooltip("#val#<br>bugs fixed");
    bar2.setText("bugs fixed");
    bar2.setFontSize(15);
    bar1.setAlpha(0.9f);
    bar2.addValues(2,7,1,5,8,3,0,2);

    Chart chart2 = new Chart("Beers and bugs");
    chart2.addElements(bar1,bar2);
    chart2.setBackgroundColour("#FFFFFF");

    add(new OpenFlashChart("chart2", 300,400,chart2));

  }
}

Accompanying html:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/" lang="en">
<head>
  <title>Wicket Open Flash Chart Demo</title>
</head>

<body>
<strong>Open Flash Chart Demo</strong>
<br/><br/>
<div wicket:id="message">message will be here</div>

<div wicket:id="chart1" >chart will be here</div>

<div wicket:id="chart2" >chart will be here</div>
</body>
</html>

I have attached a working Wicket Quickstart project that already includes the code above.
If you want to try it out:


TODO: compare my version with the one by Ryan McKinley. I think it's pretty much the same.


/**
 * @see <a href="http://code.google.com/p/swfobject/">SWFObject</a>
 */
public class OpenFlashChart extends Panel implements IResourceListener
{
  static final ResourceReference SWF = new ResourceReference( OpenFlashChart.class, "open-flash-chart.swf" );
  
  final WebResource jsonResource;
  final SWFObject swf;
  final IModel<Chart> chart;

  public OpenFlashChart(final String id, final IModel<Chart> chart, final int width, final int height) 
  {
    this( id, chart, width+"", height+"" );
  }
  
  public OpenFlashChart(final String id, final IModel<Chart> chart, final String width, final String height) 
  {
    super(id);
    this.chart = chart;
    
    final IResourceStream json = new AbstractStringResourceStream( "text/plain") {
      @Override
      public String getString() {
        return chart.getObject().toString();
      }
    };

    jsonResource = new WebResource() {
      @Override
      public IResourceStream getResourceStream() {
        return json;
      }
    };
    jsonResource.setCacheable(false);
    
    String swfURL = RequestUtils.toAbsolutePath( urlFor( SWF ).toString() );
    swf = new SWFObject( "chart", swfURL, "500", "300" );
    add( swf );
  }
  
  @Override
  protected void onBeforeRender() {
    CharSequence dataPath = 
      RequestCycle.get().urlFor(OpenFlashChart.this, IResourceListener.INTERFACE); 
    
    String data = RequestUtils.toAbsolutePath( dataPath.toString() );
    
    swf.setFlashvar( "data-file", data );
    swf.setParam( "allowScriptAccess", "sameDomain" );
    
    super.onBeforeRender();
  }

  /**
   * Actually handle the request
   */
  public void onResourceRequested() {
    jsonResource.onResourceRequested();
  }
}

  • No labels