/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.tuwien.ifs.somtoolbox.apps.viewer;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.text.AttributedString;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.util.PaintList;
import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.PCanvas;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.util.PPaintContext;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.MapOverviewPane;
/**
* Wrapper for displaying a pie chart within the Piccolo zooming interface framework.
*
* @author Michael Dittenbach
* @version $Id: PieChartPNode.java 3939 2010-11-17 16:06:14Z frank $
*/
public class PieChartPNode extends PNode {
public enum PieChartLabelMode {
None, Count, Percent
}
private static final long serialVersionUID = 1L;
private int[] values = null;
private int itemCount;
private PiePlot plot;
private Rectangle2D border = new Rectangle2D.Double();
private double X = 0;
private double Y = 0;
private double width = 0;
private double height = 0;
private final CountLabeler countLabeler = new CountLabeler();
private final PercentageLabeler percentageLabeler = new PercentageLabeler();
/**
* Creates a PieChartPNode at the given coordinates with the given values.
*
* @param x X coordinate of the chart.
* @param y Y coordinate of the chart.
* @param values Array of <code>double</code> containing the values.
*/
public PieChartPNode(double x, double y, double w, double h, int[] values, int itemCount) {
super();
X = x;
Y = y;
width = w;
height = h;
this.values = values;
this.itemCount = itemCount;
plot = createPiechartPlot(values);
setShowLegend(PieChartLabelMode.None);
this.setBounds(X, Y, width, height);
// TODO: check id values == null
}
/** Creates a piechart from the given count values */
public static PiePlot createPiechartPlot(int[] values) {
DefaultPieDataset dataset = new DefaultPieDataset();
for (int i = 0; i < values.length; i++) {
dataset.setValue(String.valueOf(i), values[i]);
}
PiePlot piePlot = new PiePlot(dataset);
piePlot.setShadowPaint(null);
piePlot.setBackgroundPaint(null);
piePlot.setOutlinePaint(null);
piePlot.setIgnoreZeroValues(true); // makes sure we have no labels for sections with zero values..
piePlot.setIgnoreNullValues(true);
piePlot.setSectionOutlinesVisible(false); // hides the border around each pie slice
piePlot.setLabelGenerator(null);
return piePlot;
}
/**
* Draw pie-charts on the given {@link Graphics2D} object, with the provided values and colours, and unit width.
* Used when exporting pie charts as stand-alone image, or for superimposing them on an exported visualisation.
*/
public static void drawPlot(Graphics2D g2d, int[] values, Color[] colors, double x, double y, double width,
double height) {
PiePlot piePlot = createPiechartPlot(values);
piePlot.setLabelGap(0);
piePlot.setInteriorGap(0);
for (int i = 0; i < colors.length; i++) {
if (colors[i] != null) {
piePlot.setSectionPaint(i, colors[i]);
}
}
piePlot.draw(g2d, new Rectangle2D.Double(x, y, width, height), null, null, null);
}
@Override
public boolean setBounds(double x, double y, double width, double height) {
if (super.setBounds(x, y, width, height)) {
border.setFrame(x, y, width, height);
this.X = x;
this.Y = y;
this.width = width;
this.height = height;
return true;
}
return false;
}
@Override
protected void paint(PPaintContext paintContext) {
PCamera pCam = paintContext.getCamera();
// paint only for the main display, not the MapOverviewPane
if (!((PCanvas) pCam.getComponent()).getClass().equals(MapOverviewPane.MapOverviewCanvas.class)) {
Graphics2D g2d = paintContext.getGraphics();
border.setRect(X, Y, width, height);
plot.draw(g2d, new Rectangle2D.Double(X, Y, width, height), null, null, null);
}
}
/**
* Returns the colors used in the diagram. Can be used for a legend displayed in a different Swing element.
*
* @return Array of <code>Color</code>.
*/
public Color[] getLegendColors() {
Color[] res = new Color[values.length];
for (int i = 0; i < values.length; i++) {
res[i] = (Color) plot.getSectionPaint(i);
}
return res;
}
public PaintList getPaintList() {
PaintList p = new PaintList();
for (int i = 0; i < values.length; i++) {
p.setPaint(i, plot.getSectionPaint(i));
}
return p;
}
/** Returns the colour used in the diagram at the specified index. */
public Color getLegendColor(int index) {
return (Color) plot.getSectionPaint(index);
}
public void setColor(int index, Color color) {
plot.setSectionPaint(index, color);
}
public void setColors(Color[] colors) {
for (int i = 0; i < colors.length; i++) {
plot.setSectionPaint(i, colors[i]);
}
}
public int[] getValues() {
return values;
}
public void setShowLegend(PieChartLabelMode mode) {
switch (mode) {
case Count:
plot.setLabelGenerator(countLabeler);
break;
case Percent:
plot.setLabelGenerator(percentageLabeler);
break;
case None:
plot.setLabelGenerator(null);
break;
}
}
@SuppressWarnings("rawtypes")
private class CountLabeler implements PieSectionLabelGenerator {
@Override
public String generateSectionLabel(PieDataset dataset, Comparable key) {
return String.valueOf(dataset.getValue(key).intValue());
}
@Override
public AttributedString generateAttributedSectionLabel(PieDataset dataset, Comparable key) {
return null;
}
}
@SuppressWarnings("rawtypes")
private class PercentageLabeler implements PieSectionLabelGenerator {
@Override
public String generateSectionLabel(PieDataset dataset, Comparable key) {
return String.valueOf(Math.round(100 * dataset.getValue(key).doubleValue() / itemCount) + "%");
}
@Override
public AttributedString generateAttributedSectionLabel(PieDataset dataset, Comparable key) {
return null;
}
}
}