All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.opensuit.xml.chart.XYChart Maven / Gradle / Ivy

There is a newer version: 1.0.3
Show newest version
/**
 * Open SUIT - Simple User Interface Toolkit
 * 
 * Copyright (c) 2009 EBM Websourcing, http://www.ebmwebsourcing.com/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.ow2.opensuit.xml.chart;

import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PolarPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.DefaultPolarItemRenderer;
import org.jfree.chart.renderer.xy.XYAreaRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYStepAreaRenderer;
import org.jfree.chart.renderer.xy.XYStepRenderer;
import org.jfree.chart.urls.XYURLGenerator;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.RectangleInsets;
import org.ow2.opensuit.core.session.OpenSuitSession;
import org.ow2.opensuit.core.util.ReflectionHelper;
import org.ow2.opensuit.xml.base.action.IAction;
import org.ow2.opensuit.xml.base.binding.Expression;
import org.ow2.opensuit.xml.interfaces.IBeanProvider;
import org.ow2.opensuit.xmlmap.annotations.XmlAttribute;
import org.ow2.opensuit.xmlmap.annotations.XmlChild;
import org.ow2.opensuit.xmlmap.annotations.XmlDoc;
import org.ow2.opensuit.xmlmap.annotations.XmlElement;
import org.ow2.opensuit.xmlmap.interfaces.IInitializationSupport;
import org.ow2.opensuit.xmlmap.interfaces.IInstantiationContext;

@XmlElement
public class XYChart extends BaseChart implements IBeanProvider
{
	@XmlDoc("The name of the serie contextual bean.
" + "This bean is available at render-time only.
" + "Default: $serie.") @XmlAttribute(name="SerieVar", required=false) private String serieVar= "$serie"; @XmlDoc("The name of the x value contextual bean.
" + "This bean is available at render-time only.
" + "Default: $x.") @XmlAttribute(name="XVar", required=false) private String xVar= "$x"; @XmlDoc("The name of the y value contextual bean.
" + "This bean is available at render-time only.
" + "Default: $y.") @XmlAttribute(name="YVar", required=false) private String yVar= "$y"; @XmlDoc("Determines the chart style.
" + "Default: XYLine.") @XmlAttribute(name="Style", required=false) private XYChartStyle style= XYChartStyle.XYLine; @XmlDoc("Determines the chart orientation.
" + "Default: horizontal.") @XmlAttribute(name="Orientation", required=false) private Orientation orientation= Orientation.Horizontal; @XmlDoc("Defines the x axis label.") @XmlChild(name="XAxisLabel") protected Expression xAxisLabel; @XmlDoc("Defines the y axis label.") @XmlChild(name="YAxisLabel") protected Expression yAxisLabel; @XmlDoc("Gives a vector of items representing x,y series to display.") @XmlChild(name="Series") protected Expression series; @XmlDoc("Evaluates the name of a given serie.
" + "Supported contextual beans: $serie") @XmlChild(name="SerieName") protected Expression serieName; @XmlDoc("Returns the x,y values of a given serie.
" + "The expected return type is double[2][]." + "Must be an array with length 2, containing two arrays of equal length, the first containing the x-values and the second containing the y-values" + "Supported contextual beans: $serie") @XmlChild(name="SerieValues") protected Expression serieValues; @XmlDoc("Defines the tooltip for a given x,y value.
" + "Supported contextual beans: $serie, $x, $y") @XmlChild(name = "ValueTooltip", required = false) protected Expression valueTooltip; @XmlDoc("Defines the action to perform when a given x,y value is clicked.
" + "Supported contextual beans: $serie, $x, $y") @XmlChild(name = "OnClickValue", required = false) protected IAction onClickValue; private Type itemType; private Class itemClass; public void initialize(IInitializationSupport initSupport, IInstantiationContext instContext) { super.initialize(initSupport, instContext); if(initSupport.initialize(series)) { itemClass = ReflectionHelper.getVectorElementClass(series.getGenericType()); if(itemClass == null) { initSupport.addValidationMessage(this, "IterateOn", IInitializationSupport.ERROR, "Expression 'IterateOn' must return vector data."); } else { itemType = ReflectionHelper.getVectorElementType(series.getGenericType()); // --- check itemValue return a double[][] /* if(serieValues != null && initSupport.initialize(serieValues)) { if(!serieValues.isConvertible(Number.class)) { initSupport.addValidationMessage(this, "SerieValues", IInitializationSupport.ERROR, "Expression 'SerieValues' must return a Number."); } else { valueType = serieValues.getGenericType(); valueClass = serieValues.getType(); } } */ } } } @Override public Plot makePlot(HttpServletRequest request) throws Exception { // --- 1: make dataset Collection itemObjs = ReflectionHelper.obj2Collection(series.invoke(request)); if(itemObjs == null){ return null; } String xAxisLabel = this.xAxisLabel.invoke(request, String.class); String yAxisLabel = this.yAxisLabel.invoke(request, String.class); PlotOrientation orientation = this.orientation.getPlotOrientation(); DefaultXYDataset dataset = new DefaultXYDataset(); int i=0; for(Object item : itemObjs) { // --- set iterator var request.setAttribute(serieVar, item); Key key = new Key(); key.item = item; key.name = serieName.invoke(request, String.class); key.index = i++; double[][] values = (double[][])serieValues.invoke(request); dataset.addSeries(key, values); } // --- 2: make plot // Polar, Scatter, TimeSeries, XYArea, XYLine, XYStepArea, XYStep if(style == XYChartStyle.Polar) { // return ChartFactory.createPolarChart(title, dataSet, showLegend, renderTooltips, renderUrls); PolarPlot pplot = new PolarPlot(); pplot.setDataset(dataset); NumberAxis rangeAxis = new NumberAxis(); rangeAxis.setAxisLineVisible(false); rangeAxis.setTickMarksVisible(false); rangeAxis.setTickLabelInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0)); pplot.setAxis(rangeAxis); pplot.setRenderer(new DefaultPolarItemRenderer()); // --- no tooltip nor url return pplot; } XYPlot plot = null; if(style == XYChartStyle.Scatter) { // return ChartFactory.createScatterPlot(title, xAxisLabel, yAxisLabel, dataset, orientation.getPlotOrientation(), showLegend, renderTooltips, renderUrls); NumberAxis xAxis = new NumberAxis(xAxisLabel); xAxis.setAutoRangeIncludesZero(false); NumberAxis yAxis = new NumberAxis(yAxisLabel); yAxis.setAutoRangeIncludesZero(false); plot = new XYPlot(dataset, xAxis, yAxis, null); XYItemRenderer renderer = new XYLineAndShapeRenderer(false, true); plot.setRenderer(renderer); plot.setOrientation(orientation); } else if(style == XYChartStyle.TimeSeries) { // return ChartFactory.createTimeSeriesChart(title, xAxisLabel, yAxisLabel, dataset, showLegend, renderTooltips, renderUrls); ValueAxis timeAxis = new DateAxis(xAxisLabel); timeAxis.setLowerMargin(0.02); // reduce the default margins timeAxis.setUpperMargin(0.02); NumberAxis valueAxis = new NumberAxis(yAxisLabel); valueAxis.setAutoRangeIncludesZero(false); // override default plot = new XYPlot(dataset, timeAxis, valueAxis, null); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false); plot.setRenderer(renderer); } else if(style == XYChartStyle.XYArea) { // return ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation.getPlotOrientation(), showLegend, renderTooltips, renderUrls); NumberAxis xAxis = new NumberAxis(xAxisLabel); xAxis.setAutoRangeIncludesZero(false); NumberAxis yAxis = new NumberAxis(yAxisLabel); plot = new XYPlot(dataset, xAxis, yAxis, null); plot.setOrientation(orientation); plot.setForegroundAlpha(0.5f); plot.setRenderer(new XYAreaRenderer(XYAreaRenderer.AREA)); } else if(style == XYChartStyle.XYLine) { NumberAxis xAxis = new NumberAxis(xAxisLabel); xAxis.setAutoRangeIncludesZero(false); NumberAxis yAxis = new NumberAxis(yAxisLabel); XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false); plot = new XYPlot(dataset, xAxis, yAxis, renderer); plot.setOrientation(orientation); } else if(style == XYChartStyle.XYStepArea) { // return ChartFactory.createXYStepAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation.getPlotOrientation(), showLegend, renderTooltips, renderUrls); NumberAxis xAxis = new NumberAxis(xAxisLabel); xAxis.setAutoRangeIncludesZero(false); NumberAxis yAxis = new NumberAxis(yAxisLabel); XYItemRenderer renderer = new XYStepAreaRenderer(XYStepAreaRenderer.AREA_AND_SHAPES); plot = new XYPlot(dataset, xAxis, yAxis, null); plot.setRenderer(renderer); plot.setOrientation(orientation); plot.setDomainCrosshairVisible(false); plot.setRangeCrosshairVisible(false); } else // XYStep { // return ChartFactory.createXYStepChart(title, xAxisLabel, yAxisLabel, dataset, orientation.getPlotOrientation(), showLegend, renderTooltips, renderUrls); DateAxis xAxis = new DateAxis(xAxisLabel); NumberAxis yAxis = new NumberAxis(yAxisLabel); yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); XYItemRenderer renderer = new XYStepRenderer(); plot = new XYPlot(dataset, xAxis, yAxis, null); plot.setRenderer(renderer); plot.setOrientation(orientation); plot.setDomainCrosshairVisible(false); plot.setRangeCrosshairVisible(false); } // --- 3: apply generators // --- add the tooltip generator if (valueTooltip != null) { plot.getRenderer().setBaseToolTipGenerator(new TooltipGenerator()); } else { // --- apply default tooltip generator plot.getRenderer().setBaseToolTipGenerator(new StandardXYToolTipGenerator()); } // --- add the url generator if (onClickValue != null){ plot.getRenderer().setURLGenerator(new URLGenerator()); } return plot; } // ========================================================================== // === Key // ========================================================================== private static class Key implements Comparable { private String name; private Object item; private int index; public int compareTo(Key o) { return index - o.index; } @Override public String toString() { return name; } @Override public boolean equals(Object obj) { if(obj == null || !(obj instanceof Key)){ return false; } return item.equals(((Key)obj).item); } @Override public int hashCode() { return item.hashCode(); } } // ========================================================================== // === TooltipGenerator // ========================================================================== private class TooltipGenerator implements XYToolTipGenerator { public String generateToolTip(XYDataset dataset, int series, int item) { HttpServletRequest request = OpenSuitSession.getCurrentRequest(); Key serieKey = (Key) dataset.getSeriesKey(series); Number x = dataset.getX(series, item); Number y = dataset.getY(series, item); // --- set contextual beans request.setAttribute(serieVar, serieKey.item); request.setAttribute(xVar, x); request.setAttribute(yVar, y); // --- then eval tooltip try { return valueTooltip.invoke(request, String.class); } catch (Exception e) { logger.error("Error while evaluating item tooltip.", e); return null; } } } // ========================================================================== // === UrlGenerator // ========================================================================== private class URLGenerator implements XYURLGenerator { public String generateURL(XYDataset dataset, int series, int item) { HttpServletRequest request = OpenSuitSession.getCurrentRequest(); Key serieKey = (Key) dataset.getSeriesKey(series); Number x = dataset.getX(series, item); Number y = dataset.getY(series, item); // --- set contextual beans request.setAttribute(serieVar, serieKey.item); request.setAttribute(xVar, x); request.setAttribute(yVar, y); // --- then eval url try { return onClickValue.getURL(request, true); } catch (Exception e) { logger.error("Error while evaluating onclick action.", e); return null; } } } // ================================================================================= // === IBeanProvider // ================================================================================= @Override public Class getBeanType(String iName) throws UnresolvedBeanError { if(serieVar.equals(iName)) { if(itemClass == null){ throw new UnresolvedBeanError(); } return itemClass; } else if(xVar.equals(iName) || yVar.equals(iName)) { return Number.class; } return super.getBeanType(iName); } @Override public Type getBeanGenericType(String iName) throws UnresolvedBeanError { if(serieVar.equals(iName)) { if(itemType == null){ throw new UnresolvedBeanError(); } return itemType; } else if(xVar.equals(iName) || yVar.equals(iName)) { return Number.class; } return super.getBeanGenericType(iName); } @Override public Object getBeanValue(HttpServletRequest iRequest, String iName) throws Exception { if(serieVar.equals(iName)){ return iRequest.getAttribute(iName); }else if(xVar.equals(iName) || yVar.equals(iName)){ return iRequest.getAttribute(iName); } return super.getBeanValue(iRequest, iName); } @Override public List getBeanNames() { List names = super.getBeanNames(); names.add(serieVar); names.add(xVar); names.add(yVar); return names; } @Override public String getBeanDescription(String name) { if(serieVar.equals(name)) { return "The <XYChart> series contextual bean.
" + "This bean is available at render-time only.
" + "Class: "+(itemClass == null ? "unresolved!" : itemClass.getName()); } else if (xVar.equals(name)) { return "The <XYChart> X contextual bean.
" + "This bean is available at render-time only.
" + "Class: java.lang.Number"; } else if (yVar.equals(name)) { return "The <XYChart> Y contextual bean.
" + "This bean is available at render-time only.
" + "Class: java.lang.Number"; } // TODO Auto-generated method stub return super.getBeanDescription(name); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy