DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Popular
  3. Open Source
  4. Custom Facelets Chart Component Using Open Source Flash

Custom Facelets Chart Component Using Open Source Flash

Munish Gogna user avatar by
Munish Gogna
·
Dec. 13, 10 · Interview
Like (0)
Save
Tweet
Share
7.05K Views

Join the DZone community and get the full member experience.

Join For Free
You must have heard the old maxim that there are lies, damned lies, statistics and Excel charts - well, anyone who's ever tried to do any kind of serious reporting of statistics on the web knows that you need to be able to produce good graphs. For years there have been libraries such as JFreeChart that do a reasonable job of graph-drawing in static image way, in recent years arrival of Google Analytics (google finance's price history chart e.g.) raised the quality bar substantially. Suddenly everyone including your line manager wanted fancy line graphs that show the numbers represented by each point when you roll the mouse along the line (I am not going to use google charts as it requires internet connection to draw charts. If your application is installed in some secured environment where the outside connectivity is not allowed than you are in big trouble).

After googling for some time I came across Open Flash Chart Project (http://teethgrinder.co.uk/open-flash-chart). Open Flash Chart lets everyone have interactive Flash charts on their website. So today I am going to discuss how we can use open source flash to create stunning flash charts in Java. I am going to develop a JSF facelet component that can be easily plugged into any JSF application. The best part about the Open Flash chart is that it consumes JSON data, so the component that I am going to develop will be able to handle any type of chart (pie, bar, line etc.), we just need to feed chart data in JSON format and rest will be taken care by the component.

Custom Chart Component
A custom JSF component is represented by a Java Class that extends from UIComponentBase. An instance of this class is created whenever a new page is rendered that contains the component. I am not going into details of how we create the custom components. Let's move straight to the Component definition.
package gognamunish.jofc.poc;

import java.io.IOException;

import javax.el.ValueExpression;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

/**
* Custom chart component for Open Source Flash
*
* @author Munish Gogna
*
*/
public class JOFCChartUIComponent extends UIComponentBase {

private static final String COMPONENT_FAMILY = "JOFCChart";

private String width = "400"; // default width
private String height = "400"; // default height
private String jsonSource;

@Override
public void encodeBegin(FacesContext context) throws IOException {
super.encodeBegin(context);

final ResponseWriter writer = context.getResponseWriter();

writer.startElement("script type=\"text/javascript\" src=\"../jofc/js/swfobject.js\"",this);
writer.endElement("script");
writer.startElement("script type=\"text/javascript\" src=\"../jofc/js/json2.js\"",this);
writer.endElement("script");
writer.startElement("script type=\"text/javascript\"", this);
writer.write("swfobject.embedSWF (");
writer.write("\"../jofc/open-flash-chart.swf\", \"jofc_chart\",");
writer.write("\"" + getWidth() + " \", \"" + getHeight() + " \", \"9.0.0\", \"expressInstall.swf\", ");
writer.write("{\"get-data\":\"ofc_get_data\"} );");
writer.write("function ofc_get_data() { return JSON.stringify( " +getJSONSource() + ");}");
writer.endElement("script");
}

@Override
public void encodeEnd(FacesContext context) throws IOException {
super.encodeEnd(context);
}

@Override
public Object saveState(FacesContext facesContext) {
Object values[] = new Object[4];
values[0] = super.saveState(facesContext);
values[1] = this.getAttributes().get(JOFCChart.WIDTH);
values[2] = this.getAttributes().get(JOFCChart.HEIGHT);
values[3] = this.getAttributes().get(JOFCChart.JSON_SOURCE);
return values;

}

@Override
public void restoreState(FacesContext facesContext, Object state) {
Object values[] = (Object[]) state;
super.restoreState(facesContext, values[0]);
this.getAttributes().put(JOFCChart.WIDTH, values[1]);
this.getAttributes().put(JOFCChart.HEIGHT, values[2]);
this.getAttributes().put(JOFCChart.JSON_SOURCE, values[3]);
}

@Override
public String getFamily() {
return COMPONENT_FAMILY;
}

public String getWidth() {
ValueExpression ve = getValueExpression(JOFCChart.WIDTH);
if (ve != null) {
return (String) ve.getValue(getFacesContext().getELContext());
}
return width;
}

public String getJSONSource() {
ValueExpression ve = getValueExpression(JOFCChart.JSON_SOURCE);
if (ve != null) {
return (String) ve.getValue(getFacesContext().getELContext());
}
return jsonSource;
}


public String getHeight() {
ValueExpression ve = getValueExpression(JOFCChart.HEIGHT);
if (ve != null) {
return (String) ve.getValue(getFacesContext().getELContext());
}
return height;
}


public void setWidth(String width) {
this.width = width;
}

public void setHeight(String height) {
this.height = height;
}

public void setJsonSource(String jsonSource) {
this.jsonSource = jsonSource;
}
}
Note: Please note that we have not defined any separate renderer for our component, the component renders html on its own.

Let's define the descriptor for our custom facelet component - jofc_taglib.xml
<facelet-taglib>
<namespace> http://gognamunish.jofc.poc </namespace>
<tag>
<tag-name>chart</tag-name>
<component>
<component-type>JOFCChart</component-type>
</component>
</tag>
</facelet-taglib>
JSF Facelets components need to be registered in a both web.xml and faces-config.xml files.

web.xml entry:
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/jofc_taglib.xml</param-value>
</context-param>
faces-config entry:
<component>
<component-type>JOFCChart</component-type>
<component-class>gognamunish.jofc.poc.JOFCChartUIComponent</component-class>
</component>
JSON data generation
As I told earlier that Open Flash works with JSON data which means we will have to feed our custom chart component with some JSON data. We have two options here, either we create JSON data ourselves or use some library. I chose second option i.e. http://code.google.com/p/jofc2/ Java API. This library is not 100% stable and has got few bugs (read between the lines in the next java code).

Let's try to plot sample admissions data for the month of October 2010 using line chart. This example demonstrates several of the things that you can do with Line Charts.
package gognamunish.jofc.data;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import jofc2.OFC;
import jofc2.model.Chart;
import jofc2.model.Text;
import jofc2.model.axis.Label;
import jofc2.model.axis.XAxis;
import jofc2.model.axis.XAxisLabels;
import jofc2.model.axis.YAxis;
import jofc2.model.axis.Label.Rotation;
import jofc2.model.elements.LineChart;
import jofc2.model.elements.LineChart.Dot;

/**
* Source class for our sample Admission chart
*
* @author Munish Gogna
*
*/
public class DataSource {

private List admissionDataList;

/**
* Returns the JSON data which defines the elements of the OFC2 charts.
*/
public String getJOFCChartData() {
Chart chart = new Chart();
chart.setTitle(new Text("Admission Data for October 2010"));
XAxis xAxis = new XAxis();
XAxisLabels xAxisLabels = new XAxisLabels();
xAxisLabels.addLabels(getXLabels());
xAxis.setXAxisLabels(xAxisLabels);
chart.setXAxis(xAxis);

YAxis yAxis = new YAxis();
yAxis.setMax(getAdmissionList().size() + 1);
chart.setYAxis(yAxis);

LineChart lineChart = new LineChart();
lineChart.setText("copyright: Munish Gogna 2010");
lineChart.addDots(getValues());
lineChart.setFontSize(10);

chart.addElements(lineChart);

// JOFC API BUG - The enum Rotation.VERTICAL should have value 90 as opposed to -90
return OFC.getInstance().render(chart).replace("-90", "90");
}

private List getXLabels() {
List xLabelsList = new ArrayList();
for (AdmissionData cd : getAdmissionList()) {
Label label = new Label();
label.setText(cd.month);
// for displaying the X labels vertically
label.setRotation(Rotation.VERTICAL);
xLabelsList.add(label);
}
return xLabelsList;
}

private List getValues() {
List valuesList = new ArrayList();
Dot dot;
for (AdmissionData cd : getAdmissionList()) {
dot = new Dot(cd.noOfStudents);
dot.setTooltip("#val# on #x_label#");
dot.setDotSize(2);
dot.setHaloSize(3);
dot.setColour("#FF0000");
valuesList.add(dot);
}
return valuesList;
}

private List getAdmissionList() {
if (admissionDataList == null) {
admissionDataList = new ArrayList();
Random random = new Random();
AdmissionData data;
for (int i = 1; i <= 30; i++) {
data = new AdmissionData("October" + i, random.nextInt(30));
admissionDataList.add(data);
}
}
return admissionDataList;
}

/** helper class for plotting admission related data */
static class AdmissionData {

public String month;
public int noOfStudents;

AdmissionData(String month, int noOfStudents) {
this.month = month;
this.noOfStudents = noOfStudents;
}
}
}

In absence of JOFC2 Java API library we would have to provide following json string to our chart component for the line chart we are looking for. Don't be scared JSON is not meant to be consumed by human :)
{"is_thousand_separator_disabled":0,"is_decimal_separator_comma":0,"title":{"text":"Admission Data for October 2010"},"y_axis":{"max":31},"x_axis":

{"labels":{"labels":[{"text":"October1","rotate":"90"},{"text":"October2","rotate":"90"},{"text":"October3","rotate":"90"},

{"text":"October4","rotate":"90"},{"text":"October5","rotate":"90"},{"text":"October6","rotate":"90"},{"text":"October7","rotate":"90"},

{"text":"October8","rotate":"90"},{"text":"October9","rotate":"90"},{"text":"October10","rotate":"90"},{"text":"October11","rotate":"90"},

{"text":"October12","rotate":"90"},{"text":"October13","rotate":"90"},{"text":"October14","rotate":"90"},{"text":"October15","rotate":"90"},

{"text":"October16","rotate":"90"},{"text":"October17","rotate":"90"},{"text":"October18","rotate":"90"},{"text":"October19","rotate":"90"},

{"text":"October20","rotate":"90"},{"text":"October21","rotate":"90"},{"text":"October22","rotate":"90"},{"text":"October23","rotate":"90"},

{"text":"October24","rotate":"90"},{"text":"October25","rotate":"90"},{"text":"October26","rotate":"90"},{"text":"October27","rotate":"90"},

{"text":"October28","rotate":"90"},{"text":"October29","rotate":"90"},

{"text":"October30","rotate":"90"}]}},"num_decimals":2,"is_fixed_num_decimals_forced":0,"elements":[{"font-size":10,"text":"copyright: Munish Gogna

2010","type":"line","dot-style":{"halo-size":2,"type":"solid-dot","dot-size":2},"on-show":{"type":""},"values":[{"value":15,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":16,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":14,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":25,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":28,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":6,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":23,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":6,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":20,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":21,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":24,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":3,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":17,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":25,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":13,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":15,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":23,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":1,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":23,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":18,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":20,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":7,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":5,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":8,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":11,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":2,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":11,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":7,"halo-

size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"},{"value":2,"halo-size":3,"tip":"#val# on #x_label#","dot-

size":2,"colour":"#FF0000"},{"value":7,"halo-size":3,"tip":"#val# on #x_label#","dot-size":2,"colour":"#FF0000"}],"loop":false}]}


So far so good, let's see how our chart rather interactive chart looks like?

Last step - using the component
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:jofc="http://gognamunish.jofc.poc"
xmlns:p="http://primefaces.prime.com.tr/ui">

<f:view contentType="text/html">
<h:body>
<jofc:chart width="500" height="400" jsonSource="#{data.JOFCChartData}" />
<div id="jofc_chart" />
</h:body>
</f:view>
</html>
and here appears the magical flash movie:
admission chart

What you see above is a static image but in reality you will get a flash movie, as we move the mouse along the line the tool tip changes accordingly (at the time of taking this screenshot mouse pointer was on October 24)

This was just a poc , this component can be improved in many ways. I leave the rest to you guys.
Chart Open source Facelets

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Building the Next-Generation Data Lakehouse: 10X Performance
  • Best Navicat Alternative for Windows
  • What Is the Temporal Dead Zone In JavaScript?
  • Building Microservice in Golang

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: