Hace unos días estuve "
jugando" con Java y JMaki para crear gráficos (charts). Buscando en la red encontré el proyecto
jmaki-charting, el cual permite generar gráficos Dojo de tipo Area, Linea, Barra y Torta.
Desgraciadamente, los ejemplos de gráficos Dojo están malos, si entran en la página de
ejemplos y pinchan un enlace de gráficos Dojo verán lo siguiente:

Asi es que me propuse crear un ejemplo que si funcione y de eso se trata esta entrada.
La gracia del ejemplo que explicaré a continuación es que se hace uso de clases java para la creación de los gráficos. De ésta manera se pueden crear gráficos a partir de datos obtenidos dinámicamente de una base de datos o cualquier fuente que se quiera. Si bien el ejemplo usa datos "
duros" fácilmente se podrían modificar las clases y traer los datos de una base de datos.
También se muestra en el ejemplo la carga de los gráficos sin la necesidad de cargar una página jsp nueva, simplemente se refresca el área correspondiente y lo demás sigue igual lo que impacta positivamente en la velocidad de carga y experiencia del usuario.
Manos a la obra. Lo primero que necesitamos es
NetBeans 6.5.1 con el
JDK 1.6 update 13 (con ésta versión realicé el ejemplo). Una vez instalado hay que descargar los módulos de JMaki, para eso ir a
Tools -> Plugins y seleccionar los dos plugines de JMaki.
Una vez reiniciado NetBeans hay que descargar el
módulo jmaki-charting, abrir NetBeans e ir a
Tools -> Palette -> Add jmaki library y seleccionar el módulo previamente descargado. Una vez listo ya se pueden utilizar los gráficos Dojo en NetBeans a través de la paleta.
La aplicación es web y explicaré la lógica que hay detrás de todo. Lo primero es entender como funciona la aplicación.
Básicamente se tiene un menú donde puedes elegir el tipo de gráfico. Éste menú es un
combobox Dojo, el cual se arrastra desde la paleta al
index.jsp. Cuando se arrastra un combobox dojo se genera con valores por
default, pero eso no es muy útil, lo mejor es cargar los datos desde un
Java Bean. El java Bean utilizado es el siguiente:
package org.beans;
import org.modelo.Parametros;
/**
*
* @author metalklesk
*/
public class BeanListaCharts {
public String getValues() {
StringBuffer buffer = new StringBuffer();
buffer.append("[");
buffer.append("{label:'Area', value:'" + Parametros.AREA + "'},");
buffer.append("{label:'Barra', value:'" + Parametros.BAR + "'},");
buffer.append("{label:'Linea', value:'" + Parametros.LINE + "'},");
buffer.append("{label:'Torta', value:'" + Parametros.PIE + "'}");
buffer.append("]");
return buffer.toString();
}
}
Luego hay que ingresar la siguiente línea en el jsp para hacer uso del Bean:
<jsp:useBean id="BeanListaCharts" class="org.beans.BeanListaCharts"/>
Y luego hay que pasar del siguiente código (que viene por default al arrastrar un combobox Dojo)
<a:widget name="dojo.combobox"
value="[
{label : 'Alabama', value : 'AL'},
{label : 'California', value : 'CA'},
{label : 'New York', value : 'NY', selected : true},
{label : 'Texas', value : 'TX'}
]" />
a la siguiente forma:
<a:widget name="dojo.combobox" value="${BeanListaCharts.values}" publish="/miCombo" />
Si se fijan, el
value lo rellenamos con el método
getValues del Java Bean. Eventualmente esos datos podrían provenir de una base de datos.
El
publish es para publicar un evento asociado al combobox. Lo que sigue es programar el evento a nuestro gusto. Esto se hace en el archivo
glue.js utilizando un
subscribe, en ese archivo agregamos lo siguiente (al final):
jmaki.subscribe("/miCombo/onSelect", function(args) {
/*
*Se debe cargar el grafico desde una pagina (o servlet) externa pero dentro del dominio
*e insertarla mediante el injector.
**/
var url_ = jmaki.webRoot + '/ServletGeneradorCharts?tipoChart=' + args.value;
var injector = new jmaki.Injector();
injector.inject({url:url_, injectionPoint:"chart"});
});
Aquí utilizamos un
Injector para agregar código html dinámico en una parte específica de la página, sin tener que recargar todo de nuevo en una página nueva. El
Injector recibe como parámetros la
dirección de la página a cargar y el
lugar de la página actual en la cual será insertada.
En este caso llamamos a un
servlet al cual le pasamos como parámetro el valor recogido de la selección en el combobox.
El método
processRequest del servlet luce de la siguiente manera:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String contexto = request.getContextPath();
String seleccion = request.getParameter("tipoChart");
String chart = "No existe ese tipo de gráfico.";
if(seleccion.equalsIgnoreCase(Parametros.PIE)) {
PieChartDojoJMaki pie = new PieChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = pie.getValor();
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/pie/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/pie',name:'jmaki.charting.pie',value:" + chart + ",uuid:'jmaki_charting_pie'});</script>");
out.println("<div id="jmaki_charting_pie" class="jmCPie">");
out.println("<canvas id="jmaki_charting_pie_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else if(seleccion.equalsIgnoreCase(Parametros.AREA)) {
AreaChartDojoJMaki area = new AreaChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = area.getValor();
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/area/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/area',name:'jmaki.charting.area',value:" + chart + ",uuid:'jmaki_charting_area2'});</script>");
out.println("<div id="jmaki_charting_area2" class="jmCPie">");
out.println("<canvas id="jmaki_charting_area2_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else if(seleccion.equalsIgnoreCase(Parametros.BAR)) {
BarChartDojoJMaki bar = new BarChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = bar.getValor();
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/bar/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/bar',name:'jmaki.charting.bar',value:" + chart + ",uuid:'jmaki_charting_bar'});</script>");
out.println("<div id="jmaki_charting_bar" class="jmCPie">");
out.println("<canvas id="jmaki_charting_bar_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else if(seleccion.equalsIgnoreCase(Parametros.LINE)) {
LineChartDojoJMaki line = new LineChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = line.getValor();
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/line/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/line',name:'jmaki.charting.line',value:" + chart + ",uuid:'jmaki_charting_line'});</script>");
out.println("<div id="jmaki_charting_line" class="jmCPie">");
out.println("<canvas id="jmaki_charting_line_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else {
//si el tipo de gráfico no corresponde, notifico al usuario.
out.println("<font color="#f00">" + chart + "</font>");
out.close();
}
}
El servlet recibe el parámetro seleccionado por el usuario a través del
request.getParameter y dependiendo del valor construye un gráfico. Para obtener los valores del widget se hace uso de las clases
Cada una de éstas clases se especializa en construir un gráfico en particular, utilizando la notación definida por JMaki (Dojo en este caso). En el ejemplo se utilizan datos duros, pero al igual que el caso del combobox, fácilmente se pueden adaptar para hacer uso de una base de datos.
A continuación se puede ver el código de la clase que define un gráfico de area:
package org.modelo;
import java.util.ArrayList;
/**
*
* @author metalklesk
*/
public class AreaChartDojoJMaki {
private ArrayList<String> xEtiquetas;
private ArrayList<String> yEtiquetas;
private ArrayList<String> datos;
/**
* Constructor sin parámetros. Inicia valores predeterminados para construir un
* gráfico de ejemplo.
*/
public AreaChartDojoJMaki() {
xEtiquetas = new ArrayList<String>();
xEtiquetas.add("{label : 'Enero'}, ");
xEtiquetas.add("{label : 'Febrero'}, ");
xEtiquetas.add("{label : 'Marzo'}, ");
xEtiquetas.add("{label : 'Abril'}, ");
xEtiquetas.add("{label : 'Mayo'}, ");
xEtiquetas.add("{label : 'Junio'}, ");
xEtiquetas.add("{label : 'Julio'}, ");
xEtiquetas.add("{label : 'Agosto'}, ");
xEtiquetas.add("{label : 'Septiembre'}, ");
xEtiquetas.add("{label : 'Octubre'}, ");
xEtiquetas.add("{label : 'Noviembre'}, ");
xEtiquetas.add("{label : 'Diciembre'}");
yEtiquetas = new ArrayList<String>();
yEtiquetas.add("{ label : '0', value : 0}");
yEtiquetas.add("{ label : '10s', value : 10}");
yEtiquetas.add("{ label : '20s', value : 20}");
yEtiquetas.add("{ label : '30s', value : 30}");
yEtiquetas.add("{ label : '40s', value : 40}");
yEtiquetas.add("{ label : '50s', value : 50}");
datos = new ArrayList<String>();
datos.add("{id : 'marcador', label : 'Dataset 1', values : [25, 45, 25, 45, 50, 25, 35, 25, 25, 20, 35, 45] }");
datos.add("{label : 'Dataset 2', values : [20, 40, 30, 35, 45, 20, 25, 15, 20, 25, 30, 40] }");
datos.add("{label : 'Dataset 3', values : [15, 35, 15, 40, 30, 15, 20, 10, 15, 20, 30, 35] }");
datos.add("{label : 'Dataset 4', values : [10, 25, 10, 5, 20, 5, 15, 5, 10, 15, 25, 30] }");
}
/**
* Recibe los datos que construyen el gráfico. Se pueden ingresar varios conjuntos de datos (datasets) y la forma
* en que se ingresa cada uno es de la siguiente manera:
* "{label : '$titulo_dataset', values : [$valor1, $valor2, ..., $valorN]}", sin las comillas.
* @param datos
*/
public void setDatos(ArrayList<String> datos) {
this.datos = datos;
}
/**
* Recibe las etiquetas para la coordenada X. El formato de cada etiqueta debe ser de la siguiente forma:
* "{label: '$valor'},", sin las comillas.
* @param xEtiquetas
*/
public void setXEtiquetas(ArrayList<String> xEtiquetas) {
this.xEtiquetas = xEtiquetas;
}
/**
* Recine las etiquetas para la coordenada Y. El formato de cada etiqueta debe ser de la siguiente forma:
* "{label : '$titulo', value : $valor}"
* @param yEtiquetas
*/
public void setYEtiquetas(ArrayList<String> yEtiquetas) {
this.yEtiquetas = yEtiquetas;
}
/**
* Retorna el contenido de la etiqueta value del componente jmaki.charting.area.
* @return
*/
public String getValor() {
StringBuffer buffer = new StringBuffer();
buffer.append("{");
//valores de la coordenada x
buffer.append("xAxis : { labels : [ ");
for(int i=0; i< xEtiquetas.size(); i++) {
buffer.append(xEtiquetas.get(i));
}
buffer.append("]},");
//valores de la coordenada y
buffer.append("yAxis : { labels : [");
for(int i=0; i< yEtiquetas.size(); i++) {
buffer.append(yEtiquetas.get(i) + ", ");
}
buffer.append("]},");
//aqui agrego marcadores en algunos puntos.
buffer.append("markers : [{ targetId : 'marcador', label : '{value}', " +
"index : 5}, { targetId : 'marcador', label : '{value}', index : 6}, " +
"{ targetId : 'marcador', label : '{value}', index : 8}],");
//datos que construyen el grafico
buffer.append("data : [ ");
for(int i=0; i<datos.size(); i++) {
buffer.append(datos.get(i) + ", ");
}
buffer.append("]");
buffer.append("}");
return buffer.toString();
}
}
Como se pude ver, no es necesario utilizar objetos
JSON, un simple
String con la estructura adecuada basta para generar un chart o widget JMaki en general.
A continuación se pueden ver imágenes del ejemplo funcionando.





Como siempre pueden dejar un comentario con su dirección de correo y les envío el ejemplo completo (proyecto en NetBeans 6.5.1 comprimido) para que lo corran y vean en sus equipos.
Saludos !!!