package er.plot; import java.util.Enumeration; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.PiePlot; import org.jfree.data.general.Dataset; import org.jfree.data.general.DefaultPieDataset; import org.jfree.data.general.PieDataset; import com.webobjects.appserver.WOContext; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSKeyValueCodingAdditions; import er.extensions.foundation.ERXAssert; /** * Displays a Pie chart with an optional map. The most important binding is <code>items</code> which * should contain an array of objects from which the values <code>nameKey</code> and <code> * valueKey</code> are retrieved. For example, you might have an array of line items, * with a valueKey <code>amount</code> and a nameKey <code>product.name</code>. If you supply a * PieDataset instead, this will get used instead of the other bindings. * @binding name the name of the chart * @binding chartType the type of the chart (possible values depend on the concrete subclass) * @binding imageType the type of the image to show: <code>png</code> (default) or <code>jpeg</code> * @binding width the width of the chart (400 pixel if not specified) * @binding height the height of the chart (400 pixel if not specified) * @binding dataset Dataset to use. If this is given, then items, nameKey, valueKey and categoryKey are not considered. * @binding items array of values to display the chart for * @binding nameKey the key for the name (must return String) * @binding valueKey the key for the value (must return Number) * @binding showLegends true, if legends should be shown * @binding showLabels true, if labels should be shown (default is true) * @binding showToolTips true, if tool tips should be shown * @binding showUrls true, if urls should be shown * @binding chart Chart to use instead of the created one. If this binding is setable, then it will be set to the actually used chart * @binding configuration NSDictionary that will be applied to the chart via key-value-coding prior to rendering. Contains * entries like <code>antiAlias=true</code> or <code>categoryPlot.dataAreaRatio = 0.8</code>. * @author ak */ public class ERPPieChart extends ERPChart { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; /** logging support */ public static final NSArray<String> SUPPORTED_TYPES = new NSArray<>(new String[] {"PieChart", "PieChart3D", "RingChart"}); /** * Utility class to accomodate for accumulating data (the superclass can only replace values, * so it will always yield the latest one.) * @author ak */ public static class AccumulatingPieDataset extends DefaultPieDataset { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; /** * Overridden so it adds the value to the current value for the key instead of replacing it. */ @SuppressWarnings("unchecked") @Override public void setValue(Comparable key, Number value) { if(getIndex(key) >= 0) { Number oldValue = getValue(key); value = Double.valueOf(value.doubleValue() + oldValue.doubleValue()); } super.setValue(key, value); } } /** * Public constructor * @param context the context */ public ERPPieChart(WOContext context) { super(context); } @Override public String nameKey() { if(_nameKey == null) { _nameKey = (String)valueForBinding("nameKey"); ERXAssert.DURING.notNull("nameKey", _nameKey); } return _nameKey; } @Override public String valueKey() { if(_valueKey == null) { _valueKey = (String)valueForBinding("valueKey"); ERXAssert.DURING.notNull("valueKey", _valueKey); } return _valueKey; } @Override protected Dataset createDataset() { AccumulatingPieDataset dataset = new AccumulatingPieDataset(); for(Enumeration<?> items = items().objectEnumerator(); items.hasMoreElements(); ) { Object item = items.nextElement(); Comparable<?> name = (Comparable<?>)NSKeyValueCodingAdditions.Utility.valueForKeyPath(item, nameKey()); Number value = (Number)NSKeyValueCodingAdditions.Utility.valueForKeyPath(item, valueKey()); dataset.setValue(name, value); } return dataset; } @Override public JFreeChart createChart() { JFreeChart chart = null; PieDataset dataset = (PieDataset)dataset(); String name = stringValueForBinding("name", null); if("PieChart3D".equals(chartType())) { chart = ChartFactory.createPieChart3D(name,dataset,showLegends(),showToolTips(),showUrls()); } else if("RingChart".equals(chartType())) { chart = ChartFactory.createRingChart(name,dataset,showLegends(),showToolTips(),showUrls()); } else { chart = ChartFactory.createPieChart(name,dataset,showLegends(),showToolTips(),showUrls()); } if(!showLabels()) ((PiePlot) chart.getPlot()).setLabelGenerator(null); return chart; } @Override protected NSArray<String> supportedTypes() { return SUPPORTED_TYPES; } public boolean showLabels() { return booleanValueForBinding("showLabels", true); } }