Índice de contenidos
- Introducción
- Preparación del entorno
- Creando gráficas con la etiqueta <outputchart>
- Generar gráficas dinámicamente
- Gráficas personalizadas
- Conclusiones
01. Introducción
ICEfaces es un entorno de representación web para aplicaciones Java Server Faces, que aumenta las capacidades del framework JSF para crear interfaces utilizando AJAX y ofrece una rica librería de componentes personalizados para mejorar la presentación de nuestras páginas.
En este tutorial nos centramos en el componente outputChart de ICEfaces, que permite la representación de gráficas circulares o de ejes. Veremos como crear gráficas utilizando la etiqueta «outputChart» en páginas JSP o por medio de código en nuestras clases Java.
Este componente utiliza internamente la librería de código abierto JCharts. Veremos también como crear gráficas más complejas con el API de JCharts y enlazarlas a componentes «outputChart».
02. Preparación del entorno
Para la realización de este tutorial se han utilizado las siguientes herramientas:
Abrimos el entorno de desarrollo y creamos un nuevo proyecto web dinámico.
Vamos a añadir el soporte para Java Server Faces, abriendo las propiedades del proyecto y seleccionando «Facetas de proyecto». Marcamos la opción para «JavaServer Faces» (y si queremos la versión 1.2).
En la parte inferior de la ventana nos aparece un enlace, indicando que se requiere configuración adicional. Lo pulsamos y nos aparece la siguiente ventana.
Dejamos la implementación JSF del servidor y añadimos la librería de componentes de ICEfaces pulsando sobre el botón «new».
Añadimos las siguientes librerías necesarias a la carpeta «WebContent/WEB-INF/lib». Todas estas librerías pueden encontrarse dentro de la carpeta lib de la distribución de ICEfaces que hemos descargado.
Ahora sólamente nos resta configurar el fichero «web.xml» para añadir el soporte de ICEfaces.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>IceFacesChart</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>Persistent Faces Servlet</servlet-name> <servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>Blocking Servlet</servlet-name> <servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Persistent Faces Servlet</servlet-name> <url-pattern>*.iface</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Persistent Faces Servlet</servlet-name> <url-pattern>/xmlhttp/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Blocking Servlet</servlet-name> <url-pattern>/block/*</url-pattern> </servlet-mapping> <listener> <listener-class>com.icesoft.faces.util.event.servlet.ContextEventRepeater</listener-class> </listener> </web-app>
Algunos componentes de ICEfaces, como outputChart, generan recursos (en este caso imágenes) que realmente no están almacenados en un fichero en el servidor. El Blocking Servlet recibirá las peticiones de esas imágenes, que se habrán generado dinámicamente, para que sean mostradas en la página.
El mapeo para las urls de la forma «/xmlhttp/*» también será necesario, especialmente al utilizar un actionListener disparado al pulsar sobre los elementos de las gráficas.
03. Creando gráficas con la etiqueta <outputchart>
Para comprobar que nuestra configuración es correcta vamos a crear una sencilla página de prueba, a la que llamaremos «prueba.jsp». En esta página vamos a insertar una gráfica gracias al componente «outputchart» de ICEfaces. La etiqueta <outputchart> debe ir dentro de un formulario, de lo contrario se producirá un error.
<f:view xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ice="http://www.icesoft.com/icefaces/component"> <ice:outputDeclaration doctypeRoot="HTML" doctypePublic="-//W3C//DTD XHTML 1.0 Transitional//EN" doctypeSystem="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta> <title>Prueba de outputChart</title> </head> <body> <ice:form> <ice:outputChart /> </ice:form> </body> </html> </f:view>
Si ponemos la etiqueta sin especificar ningún atributo, se utilizarán los valores por defecto. Esto nos mostrará una gráfica de barras parecida a la siguiente.
Como curiosidad, el color por defecto de las barras es aleatorio, y podrá cambiar si ejecutamos la aplicación varias veces.
La etiqueta «outputchart» dispone principalmente de los siguientes atributos, que nos permiten personalizar la apariencia de las gráficas.
Atributo | Subtipo | Valor | Descripción | Ejemplo | Resultado | Notas |
---|---|---|---|---|---|---|
type | circulares | «pie2d» | Gráfica circular en 2 dimensiones | <ice:outputCharttype=»pie2d»/> | Admite una única serie de datos | |
«pie3d» | Gráfica circular en 3 dimensiones | <ice:outputCharttype=»pie3d»/> | Admite una única serie de datos. No se muestra la leyenda, porque las etiquetas se muestran junto a cada rodaja | |||
de ejes | «area» | Muestra el área rellena bajo la gráfica | <ice:outputCharttype=»area» data=»40, 20, 30 : 10, 20, 10″/> | |||
«areastacked» | Muestra áreas apiladas (para varias series de datos) | <ice:outputCharttype=»areastacked»data=»40, 20, 30 : 10, 20, 10″/> | ||||
«bar» | Diagrama simple de barras | <ice:outputCharttype=»bar» data=»40, 20, 30″/> | ||||
«barclustered» | Muestra unas barras al lado de las otras (para varias series de datos) | <ice:outputCharttype=»barclustered»data=»40, 20, 30 : 10, 20, 50 : 20, 30, 40″/> | ||||
«barstacked» | Muestra barras apiladas unas sobre otras (para varias series de datos) | <ice:outputCharttype=»barstacked»data=»10, 20, 30 : 30, 30, 10″/> | ||||
«line» | Muestra puntos y líneas entre ellos | <ice:outputCharttype=»line» data=»10, 20, 30 : 30, 10, 20″/> | ||||
«point» | Muestra sólamente puntos | <ice:outputCharttype=»point» data=»10, 20, 30 : 30, 10, 20″/> | ||||
«custom» | Diagrama personalizado | Ver apartado degráficas personalizadas | ||||
chartTitle | String | Título de la gráfica | <ice:outputChart type=»pie3d»chartTitle=»TITULO»height=»200″/> | |||
labels | String [] List<String> |
Nombres de las etiquetas de la gráfica. Debe haber una etiqueta por cada serie de datos o por cada valor en gráficas circulares |
<ice:outputChart type=»barstacked»labels=»Uno, Dos»data=»10, 20, 30 : 20, 50, 10″ /> | |||
data | double [] double [] [] List<double> List<double []> |
Valores de las series de datos. Cada serie puede separarse con «:» |
<ice:outputChart type=»barstacked» labels=»Uno, Dos»data=»38.9, 20.5 : 20, 50.0″ /> | |||
colors | String [] List<java.awt.Color> |
Colores para las diferentes series de datos o las rodajas de los gráficos circulares. Debe haber un color por cada serie de datos o por cada valor en gráficas circulares | <ice:outputChart type=»pie2d»colors=»green, red, yellow» data=»10, 20, 70″ /> | |||
height | String | Alto de la imagen generada (gráfcia completa, incluyendo títulos y etiquetas) en píxeles | <ice:outputChartheight=»200″ /> | |||
width | String | Ancho de la imagen generada en píxeles | <ice:outputChartwidth=»200″ /> | |||
legendPlacement | «top», «bottom«, «left», «right», «none» | Colocación de la leyenda. «none» indica que no se muestre | <ice:outputChartlegendPlacement=»right»/> | Sin efecto para el tipo «pie3d» | ||
legendColumns | Integer | Número de columnas que se mostrarán en la leyenda | <ice:outputChart type=»barstacked» labels=»A, B, C» data=»10 : 40 : 35″legendColumns=»2″ /> | Sin efecto para el tipo «pie3d» | ||
horizontal | boolean | Indica que las barras se muestren horizontalmente | <ice:outputChart type=»bar»horizontal=»true»/> | Sólo es válido para los tipos «bar» y «barclustered» | ||
xaxisTitle | String | Título del eje X | <ice:outputChartxaxisTitle=»Eje X»yaxisTitle=»Eje Y»/> | Válido para gráficas con ejes | ||
yaxisTitle | String | Título del eje Y | ||||
xaxisLabels | String [] List<String> |
Rótulos del eje X. Debe haber un rótulo por cada valor de las series de datos | <ice:outputChart type=»barclustered» labels=»Serie 1, Serie 2″ data=»10, 20, 30 : 15, 13, 40″xaxisLabels=»2001, 2002, 2003″/> | Válido para gráficas con ejes | ||
shapes | String [] (valores «circle», «diamond», «square» o «triangle») List<java.awt.Shape> |
Forma de los puntos para las gráficas de líneas y puntos. Debe haber tantas formas como series de datos | <ice:outputChart type=»line»shapes=»circle, triangle»data=»10, 20 : 13, 19″/> | Válido para tipos «line» y «point» | ||
renderOnSubmit | boolean | Por defecto, la gráfica se genera una vez y vuelve a obtenerse en sucesivas peticiones. Si este valor es true, se volverá a generar la gráfica. | <ice:outputChart chartTitle=»Autentia»renderOnSubmit=»true»data=»30, 40″ labels=»hola»/> | |||
styleClass | String (por defecto «iceOutChrt» o «iceOutChrt-dis» cuando el componente está deshabilitado) | Lista de clases CSS separadas por coma para el elemento. | <style type=»text/css»> .grafica { border: 10px solid red; float: right;} </style> <ice:outputChart styleClass=»grafica»/> |
|||
actionListener | String | Método que se lanzará al pulsar sobre algún elemento de la gráfica | Ver apartado degráficas personalizadas |
Por supuesto, además de insertar directamente los valores en las páginas JSP, podemos enlazar estos valores con propiedades de nuestros bean manejados, como con cualquier componente de JSF.
<ice:outputChart chartTitle="#{miBean.title}" data="#{miBean.data}" labels="#{miBean.labels}" colors="#{miBean.colors}"/>
04. Generar gráficas dinámicamente
Ahora que hemos visto cómo funciona la etiqueta OutputChart, vamos a ver un ejemplo de cómo generar componentes dinámicamente, a través de la clase «com.icesoft.faces.component.outputchart.OutputChart». Por medio de esta clase podemos asignar básicamente las mismas propiedades que con la etiqueta, pero desde nuestro código Java.
Creamos la clase «EjemploGraficas» que generará dos componentes de tipo OutputChart y los añadirá a un componente HtmlPanelGrid.
package backing; import java.awt.Color; import java.util.ArrayList; import java.util.List; import com.icesoft.faces.component.ext.HtmlPanelGrid; import com.icesoft.faces.component.outputchart.OutputChart; public class EjemploGraficas { HtmlPanelGrid panel = new HtmlPanelGrid(); /* A�adir graficas al panel */ public EjemploGraficas() { panel.getChildren().add(getEjemplo1()); panel.getChildren().add(getEjemplo2()); } /* Generar grafica circular */ public OutputChart getEjemplo1() { OutputChart outputChart = new OutputChart(); outputChart.setChartTitle("Tutoriales en Autentia"); outputChart.setType("pie2d"); outputChart.setData(new double [] {180.0, 76.0, 42.0, 28.0}); outputChart.setLabels(new String [] {"Roberto", "Alejandro", "Carlos", "Francisco Javier"}); outputChart.setColors(new String [] {"green", "blue", "cyan", "yellow"}); outputChart.setLegendPlacement("right"); outputChart.setLegendColumns(1); return outputChart; } /* Generar grafica con ejes */ public OutputChart getEjemplo2() { OutputChart outputChart = new OutputChart(); List<Color> colores = new ArrayList<Color>(); outputChart.setChartTitle("Prueba con ejes"); outputChart.setType("barclustered"); outputChart.setData(new double [] [] {new double [] {180.0, 76.0, 42.0, 28.0}, new double [] {120.0, 30.0, 10.0, 25.0}, new double [] {100.0, 40.0, 13.0, 56.0}}); outputChart.setLabels(new String [] {"Serie 1", "Serie 2", "Serie 3"}); colores.add(new Color(26, 86, 138)); colores.add(new Color(200)); colores.add(new Color(100)); outputChart.setColors(colores); outputChart.setXaxisLabels(new String [] {"L1", "L2", "L3", "L4"}); outputChart.setXaxisTitle("Eje X"); outputChart.setYaxisTitle("Eje Y"); return outputChart; } public HtmlPanelGrid getPanel() { return panel; } public void setPanel(HtmlPanelGrid panel) { this.panel = panel; } }
Modificamos el fichero «faces-config.xml» para añadir un bean manejado de la clase anterior.
<managed-bean> <managed-bean-name>ejemploGraficas</managed-bean-name> <managed-bean-class>backing.EjemploGraficas</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean>
Modificamos «prueba.jsp» de forma que sólamente contenga un panel enlazado a la propiedad «panel» de nuestro bean manejado.
<ice:form> <ice:panelGrid binding="#{ejemploGraficas.panel}" columns="2" /> </ice:form>
Cuando se muestre la JSP se ejecutará el constructor de nuestra clase, el cual añadirá las gráficas al panel. El resultado será el siguiente:
05. Gráficas personalizadas
Con lo visto hasta ahora podemos generar un amplio abanico de gráficas, personalizando casi todas sus características importantes. Pero en ocasiones, puede que eso no sea suficiente.
Si queremos generar algo más complejo como, por ejemplo, varios tipos diferentes de series (barras, líneas, áreas…) en una misma gráfica, podemos hacerlo utilizando directamente el API de «jCharts», sobre el que se apoya el componente «outputChart». De esta manera podremos generar cualquier gráfica que pueda generarse con «jCharts» y después enlazarla con nuestro componente visual.
Vamos a ver un ejemplo en el que generaremos una gráfica con series de datos que incluyan barras y líneas. Además, veremos cómo utlizar la propiedad «actionListener» del componente para disparar un evento al pulsar sobre algún valor de la gráfica.
Creamos la clase «EjemploJChart» dentro del paquete «backing»:
package backing; import java.awt.Color; import java.awt.Paint; import java.awt.Shape; import java.awt.Stroke; import javax.faces.event.ActionEvent; import org.krysalis.jcharts.axisChart.AxisChart; import org.krysalis.jcharts.chartData.AxisChartDataSet; import org.krysalis.jcharts.chartData.DataSeries; import org.krysalis.jcharts.properties.AxisProperties; import org.krysalis.jcharts.properties.ChartProperties; import org.krysalis.jcharts.properties.ClusteredBarChartProperties; import org.krysalis.jcharts.properties.LegendProperties; import org.krysalis.jcharts.properties.LineChartProperties; import org.krysalis.jcharts.properties.PointChartProperties; import org.krysalis.jcharts.types.ChartType; import com.icesoft.faces.component.outputchart.OutputChart; public class EjemploJChart { // Valores del elemento pulsado en la grafica por el usuario private String valor; // Grafica generada con jCharts, enlazada al componente private static AxisChart grafica; /* Evento disparado cuando el usuario pulse sobre un elemento de la grafica */ public void areaPulsada(ActionEvent event) { OutputChart chart = (OutputChart) event.getSource(); // Recuperamos los valores del elemento pulsado String leyenda = chart.getClickedImageMapArea().getLengendLabel(); String etiqueta = chart.getClickedImageMapArea().getXAxisLabel(); double valor = chart.getClickedImageMapArea().getValue(); // Cambiamos el valor del texo a mostrar this.valor = leyenda + " (" + etiqueta + ") = " + valor; } /* * Indica cuando debe representarse nuevamente la grafica. Recibe el * componente a representar. */ public boolean actualizar(OutputChart component) { if (grafica == null || component.getChart() == null) { generarGrafica(); // Asignamos la grafica personalizada al componente component.setChart(grafica); return true; } return false; } /* * Construye una grafica utilizando jCharts. La grafica tendra dos conjuntos * de datos diferentes, uno de barras y otro de lineas */ private void generarGrafica() { try { /********** Se establecen las propiedades generales del diagrama **********/ String [] etiquetasX = { "Enero", "Febrero", "Marzo" }; String tituloX = "Mes"; String tituloY = "Euros"; String tituloGrafica = "Gastos e ingresos"; /**************************************************************************/ DataSeries series = new DataSeries(etiquetasX, tituloX, tituloY, tituloGrafica); /********** Se construye el primer conjunto de datos (barras) **********/ String [] leyenda = { "Sueldo", "Extras", "Tickets" }; Paint [] colores = new Color[] { new Color(0xFF5566), new Color(0x00FFFF), new Color(0xFFFF00) }; double[][] datos = { { 1700, 1900, 1900 }, { 120, 220, 230 }, {180, 160, 189} }; AxisChartDataSet axisChartDataSet = new AxisChartDataSet(datos, leyenda, colores, ChartType.BAR_CLUSTERED, new ClusteredBarChartProperties()); series.addIAxisPlotDataSet(axisChartDataSet); // Se a�ade la serie /********************************************************************************/ /********** Se construye el segundo conjunto de datos (lineas) **********/ leyenda = new String[] { "Vivienda", "Transporte" }; colores = new Paint[] { new Color(0x445566), new Color(0xAABBCC) }; datos = new double[][] { { 1000, 1100, 1150 }, { 400, 560, 700 } }; Stroke[] estiloLineas = { LineChartProperties.DEFAULT_LINE_STROKE, LineChartProperties.DEFAULT_LINE_STROKE }; Shape[] estiloPuntos = { PointChartProperties.SHAPE_CIRCLE, PointChartProperties.SHAPE_SQUARE }; axisChartDataSet = new AxisChartDataSet(datos, leyenda, colores, ChartType.LINE, new LineChartProperties(estiloLineas, estiloPuntos)); series.addIAxisPlotDataSet(axisChartDataSet); // Se a�ade la serie /************************************************************************/ /********** Se construye la grafica, con propiedades por defecto **********/ grafica = new AxisChart(series, // Series de datos anteriores new ChartProperties(), // Propiedades de la grafica (por defecto) new AxisProperties(), // Propiedades de los ejes (por defecto) new LegendProperties(), // Propiedades de la leyenda (por defecto) 400, // Ancho de la grafica 500); // Alto de la grafica /*********************************************/ } catch (Exception e) { e.printStackTrace(); } } public String getValor() { return valor; } public void setValor(String valor) { this.valor = valor; } }
Esta clase genera una gráfica de ejemplo que presenta gastos e ingresos a lo largo de un trimestre. Las series de gastos se representan con líneas, mientras que las de ingresos lo hacen mediante barras verticales. Por simplicidad se han añadido únicamente dos o tres series de cada tipo.
El método actualizar es el que realiza la generación de la gráfica cuando ésta aún no se ha inicializado, e irá enlazado con la propiedad «renderOnSubmit» del componente. Cuando se vaya a visualizar el componente se llamará a este método y, si es la primera vez, se generará la gráfica.
Es importante notar que podemos tener diferentes conjuntos de datos, pero en cada uno debe cumplirse lo siguiente:
- La cardinalidad de «leyenda», «colores» y «datos» debe ser la misma, ya que se refieren a una misma serie.
- La cardinalidad de cada uno de los elementos de «datos» debe coincidir a su vez con el número de etiquetas en el eje X.
Modificamos el fichero prueba.jsp para mostrar un texto que indicará el valor pulsado sobre la gráfica y la propia gráfica:
<ice:outputText value="Valor pulsado: #{ejemploJChart.valor}"></ice:outputText> <ice:outputChart id="outputChart" type="custom" renderOnSubmit="#{ejemploJChart.actualizar}" actionListener="#{ejemploJChart.areaPulsada}" />
También debemos añadir el nuevo bean manejado dentro del fichero «faces-config.xml».
<managed-bean> <managed-bean-name>ejemploJChart</managed-bean-name> <managed-bean-class>backing.EjemploJChart</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean>
Compilamos y publicamos nuestros cambios, y arrancamos de nuevo el servidor. El resultado será una gráfica como la siguiente:
Si pulsamos sobre un elemento de la gráfica, veremos que se actualiza el texto de la parte superior:
06. Conclusiones
Las conclusiones que podemos extraer de este tutorial son las siguientes:
- Podemos utilizar el componente outputChart para crear gráficas de forma rápida y sencilla en nuestras páginas JSF.
- El componente outputChart dispone de bastantes propiedades que nos permiten configurar los datos y la apariencia de las gráficas a mostrar.
- Podemos manejar los eventos que se producen al pulsar sobre los elementos de nuestras gráficas para realizar acciones, como mostrar información ampliada, abrir otras páginas o cualquier cosa que se nos ocurra.
- Si necesitamos gráficas más sofisticadas, podemos utilizar el API de JCharts para crearlas y enlazarlas a componentes outputChart para obtener todas las ventajas que nos ofrecen JSF e ICEfaces.
Y eso es todo. Desde Autentia os animamos a utilizar este componente si necesitáis utilizar gráficas en vuestras aplicaciones, lo cual mejorará notablemente la presentación y permitirá tener un interfaz más intuitivo y amigable para los usuarios.