package net.iponweb.disthene.reader.graph; import net.iponweb.disthene.reader.beans.TimeSeries; import net.iponweb.disthene.reader.exceptions.LogarithmicScaleNotAllowed; import net.iponweb.disthene.reader.handler.parameters.RenderParameters; import net.iponweb.disthene.reader.utils.CollectionUtils; import java.awt.*; import java.awt.geom.Arc2D; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @author Andrei Ivanov */ public class PieGraph extends Graph { private double x0; private double y0; private double radius; public PieGraph(RenderParameters renderParameters, List<TimeSeries> data) { super(renderParameters, data); } @Override public byte[] drawGraph() throws LogarithmicScaleNotAllowed { // aggregate data List<Slice> slices = new ArrayList<>(); double total = 0.; for (int i = 0; i < data.size(); i++) { Double value; if (imageParameters.getPieMode().equals(PieMode.MAXIMUM)) { value = CollectionUtils.max(Arrays.asList(data.get(i).getValues())); } else if (imageParameters.getPieMode().equals(PieMode.MINIMUM)) { value = CollectionUtils.min(Arrays.asList(data.get(i).getValues())); } else { value = CollectionUtils.average(Arrays.asList(data.get(i).getValues())); } slices.add(new Slice(data.get(i).getName(), value, imageParameters.getColorList().get(i % imageParameters.getColorList().size()))); if (value != null) { total += value; } } for (Slice slice : slices) { slice.setPercent(slice.getValue() != null ? slice.getValue() / total : null); } if (!imageParameters.getTitle().isEmpty()) { drawTitle(); } List<String> legends = new ArrayList<>(); List<Color> colors = new ArrayList<>(); List<Boolean> secondYAxes = new ArrayList<>(); for (Slice slice : slices) { legends.add(slice.getName()); colors.add(slice.getColor()); secondYAxes.add(false); } drawLegend(legends, colors, secondYAxes, imageParameters.isUniqueLegend()); drawSlices(slices); drawLabels(slices); return getBytes(); } private void drawSlices(List<Slice> slices) { double theta = 90; double halfX = (xMax - xMin) / 2.0; double halfY = (yMax - yMin) / 2.0; x0 = xMin + halfX; y0 = yMin + halfY; radius = Math.min(halfX, halfY) * 0.95; for (Slice slice : slices) { if (slice.getPercent() == null) continue; double phi = theta - 360 * slice.getPercent(); Arc2D pie = new Arc2D.Double(); pie.setArcByCenter(x0, y0, radius, theta, phi - theta, Arc2D.PIE); g2d.setPaint(slice.getColor()); g2d.fill(pie); slice.setMidAngle((90-theta) + (theta - phi) / 2); theta = phi; } } private void drawLabels(List<Slice> slices) { g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); for (Slice slice : slices) { String label = null; if (imageParameters.getPieLabelsStyle().equals(PieLabelsStyle.PERCENT)) { if (slice.getPercent() == null || (slice.getPercent() * 100.0 < imageParameters.getPieLabelsMin())) continue; label = String.format("%%%.2f", slice.getPercent() * 100.0); } else if (imageParameters.getPieLabelsStyle().equals(PieLabelsStyle.NUMBER)) { if (slice.getValue() == null) continue; if (slice.getValue() < 10 && slice.getValue() != slice.getValue().intValue()) { label = String.format("%.2f", slice.getValue()); } else { label = String.valueOf(slice.getValue().intValue()); } } if (label == null) continue; double theta = slice.getMidAngle(); double x = x0 + (radius / 2) * Math.sin(Math.toRadians(theta)); double y = y0 - (radius / 2) * Math.cos(Math.toRadians(theta)); if (imageParameters.getPieLabelsOrientation().equals(PieLabelsOrientation.ROTATED)) { drawText((int) x, (int) y, label, imageParameters.getFont(), ColorTable.BLACK, HorizontalAlign.CENTER, VerticalAlign.MIDDLE, theta > 180 ? 90 + theta : theta - 90); } else { drawText((int) x, (int) y, label, imageParameters.getFont(), ColorTable.BLACK, HorizontalAlign.CENTER, VerticalAlign.MIDDLE); } } } private class Slice { private String name; private Double value; private Double percent; private Color color; private double midAngle; public Slice(String name, Double value, Color color) { this.name = name; this.value = value; this.color = color; } public String getName() { return name; } public Double getValue() { return value; } public Color getColor() { return color; } public Double getPercent() { return percent; } public void setPercent(Double percent) { this.percent = percent; } public double getMidAngle() { return midAngle; } public void setMidAngle(double midAngle) { this.midAngle = midAngle; } } }