package ch.hortis.sonar.web.charts;
import ch.hortis.sonar.model.MetricType;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
public class CombinedHistoryChart extends BaseChart {
private List<String> legends;
private Map<String, CombinedHistoryPlot> plotsPerLegend;
private Map<String, Double> minsPerPlotLegend;
private Map<String, Double> maxsPerPlotLegend;
private Stack<Color> colors = new Stack<Color>();
public CombinedHistoryChart() {
this(350, 250);
}
public CombinedHistoryChart(int width, int height) {
super(width, height);
legends = new ArrayList<String>();
plotsPerLegend = new TreeMap<String, CombinedHistoryPlot>();
minsPerPlotLegend = new HashMap<String, Double>();
maxsPerPlotLegend = new HashMap<String, Double>();
colors.push(SERIE1_COLOR);
colors.push(SERIE2_COLOR);
colors.push(SERIE3_COLOR);
colors.push(SERIE1_COLOR);
colors.push(SERIE2_COLOR);
colors.push(SERIE3_COLOR);
}
protected BufferedImage getChartImage() throws IOException {
CombinedDomainXYPlot combinedPlot = new CombinedDomainXYPlot();
combinedPlot.setGap(10);
combinedPlot.setOrientation(PlotOrientation.VERTICAL);
DateAxis dateAxis = new DateAxis();
combinedPlot.setDomainAxis(dateAxis);
dateAxis.setTickLabelPaint(BASE_COLOR);
for(String legend: legends) {
CombinedHistoryPlot plot = plotsPerLegend.get(legend);
Double min = minsPerPlotLegend.get(plot.metricName);
Double max = maxsPerPlotLegend.get(plot.metricName);
plot.configureRangeAxisForGivenType(min, max);
combinedPlot.add(plot.getPlot());
}
JFreeChart chart = new JFreeChart(null, TextTitle.DEFAULT_FONT, combinedPlot, true);
configureChart(chart, true);
return super.getBufferedImage(chart);
}
public void addMeasure(Double value, Date date, String metricName, int metricType) {
CombinedHistoryPlot plot = plotsPerLegend.get(metricName);
if (plot == null) {
MetricType type = MetricType.values()[metricType];
plot = new CombinedHistoryPlot(type, metricName, colors.pop());
plotsPerLegend.put(metricName, plot);
legends.add(metricName);
}
Double min = minsPerPlotLegend.get(metricName);
if (min == null || min > value) {
minsPerPlotLegend.put(metricName, value);
}
Double max = maxsPerPlotLegend.get(metricName);
if (max == null || max < value) {
maxsPerPlotLegend.put(metricName, value);
}
plot.series.addOrUpdate(new Day(date), value);
}
private class CombinedHistoryPlot {
private MetricType metricType;
private String metricName;
private XYPlot plot;
private TimeSeriesCollection timeSeries;
private DateAxis dateAxis;
private XYLineAndShapeRenderer renderer;
private TimeSeries series;
private CombinedHistoryPlot(MetricType metricType, String metricName, Color color) {
this.metricType = metricType;
this.metricName = metricName;
plot = new XYPlot();
timeSeries = new TimeSeriesCollection();
series = new TimeSeries(metricName);
timeSeries.addSeries(series);
configureDomainAxis();
plot.setDataset(timeSeries);
renderer = new XYLineAndShapeRenderer();
renderer.setBaseShapesVisible(false);
renderer.setSeriesStroke(0, new BasicStroke(2.0f));
renderer.setSeriesPaint(0, color);
renderer.setBaseSeriesVisibleInLegend(false);
renderer.setSeriesLinesVisible(0, true);
plot.setRenderer(renderer);
}
private void configureDomainAxis() {
dateAxis = new DateAxis();
dateAxis.setAutoRangeMinimumSize(1000.0 * 60.0 * 60.0 * 24.0 * 1.1);
dateAxis.setUpperMargin(0.1);
plot.setDomainAxis(dateAxis);
}
protected XYPlot getPlot() {
return plot;
}
protected void configureRangeAxisForGivenType(Double min, Double max) {
NumberAxis numberAxis = new NumberAxis(metricName);
numberAxis.setLabelAngle(Math.toRadians(90));
numberAxis.setAutoRangeIncludesZero(false);
numberAxis.setLabelPaint(BASE_COLOR);
numberAxis.setTickLabelPaint(BASE_COLOR);
if (metricType == MetricType.PERCENTAGE) {
numberAxis.setTickUnit(new NumberTickUnit(25, new DecimalFormat("0'%'")));
numberAxis.setUpperBound(105.0);
} else if (metricType == MetricType.DURATION_MS) {
numberAxis.setNumberFormatOverride(new
DecimalFormat("0' ms'"));
}
if (metricType != MetricType.PERCENTAGE) {
if (min != null && min > 0) {
Double lowerBound = min * (100d - 10d) / 100d;
numberAxis.setLowerBound(lowerBound);
}
if (max != null) {
Double upperBound = max * (100d + 10d) / 100d;
numberAxis.setUpperBound(upperBound);
}
}
plot.setRangeAxis(numberAxis);
}
}
}