001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2011 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.server.charts.jruby;
021
022 import org.apache.commons.lang.LocaleUtils;
023 import org.jfree.chart.JFreeChart;
024 import org.jfree.chart.axis.AxisLocation;
025 import org.jfree.chart.axis.DateAxis;
026 import org.jfree.chart.axis.NumberAxis;
027 import org.jfree.chart.plot.Marker;
028 import org.jfree.chart.plot.ValueMarker;
029 import org.jfree.chart.plot.XYPlot;
030 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
031 import org.jfree.chart.title.TextTitle;
032 import org.jfree.data.time.Day;
033 import org.jfree.data.time.TimeSeries;
034 import org.jfree.data.time.TimeSeriesCollection;
035 import org.jfree.ui.RectangleAnchor;
036 import org.jfree.ui.RectangleEdge;
037 import org.jfree.ui.RectangleInsets;
038 import org.jfree.ui.TextAnchor;
039 import org.sonar.server.charts.deprecated.BaseChart;
040
041 import java.awt.*;
042 import java.awt.image.BufferedImage;
043 import java.io.IOException;
044 import java.text.DateFormat;
045 import java.text.DecimalFormat;
046 import java.text.ParseException;
047 import java.util.Date;
048 import java.util.SortedMap;
049 import java.util.TreeMap;
050
051 public class TrendsChart extends BaseChart {
052
053 private XYPlot plot;
054 private SortedMap<Long, TimeSeries> seriesById;
055 private int percentAxisId = -1;
056 private boolean displayLegend;
057
058 public TrendsChart(int width, int height, String localeKey, boolean displayLegend) {
059 super(width, height);
060 this.displayLegend = displayLegend;
061 seriesById = new TreeMap<Long, TimeSeries>();
062 plot = new XYPlot();
063 DateAxis dateAxis = new DateAxis();
064 dateAxis.setDateFormatOverride(DateFormat.getDateInstance(DateFormat.SHORT, LocaleUtils.toLocale(localeKey)));
065 plot.setDomainAxis(dateAxis);
066 }
067
068 public void initSerie(Long serieId, String legend, boolean isPercent) {
069 TimeSeries series = new TimeSeries(legend);
070
071 int index=seriesById.size();
072 seriesById.put(serieId, series);
073
074 TimeSeriesCollection timeSeriesColl = new TimeSeriesCollection();
075 timeSeriesColl.addSeries(series);
076 plot.setDataset(index, timeSeriesColl);
077
078 if (isPercent) {
079 if (percentAxisId == -1) {
080 NumberAxis rangeAxis = new NumberAxis();
081 rangeAxis.setNumberFormatOverride(new DecimalFormat("0'%'"));
082 rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
083 rangeAxis.setUpperBound(100.0);
084 rangeAxis.setLowerBound(0.0);
085 plot.setRangeAxisLocation(index, AxisLocation.TOP_OR_LEFT);
086 plot.setRangeAxis(index, rangeAxis);
087 plot.mapDatasetToRangeAxis(index, index);
088 percentAxisId = index;
089
090 } else {
091 plot.mapDatasetToRangeAxis(index, percentAxisId);
092 }
093 } else {
094 NumberAxis rangeAxis = new NumberAxis(displayLegend ? legend : null);
095 rangeAxis.setAutoRangeIncludesZero(false);
096 rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
097 rangeAxis.setAutoRangeMinimumSize(2.0);
098 plot.setRangeAxisLocation(index, AxisLocation.TOP_OR_RIGHT);
099 plot.setRangeAxis(index, rangeAxis);
100 plot.mapDatasetToRangeAxis(index, index);
101 }
102
103 XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
104 renderer.setBaseShapesVisible(false);
105 renderer.setSeriesStroke(0, new BasicStroke(2.0f));
106 renderer.setSeriesPaint(0, COLORS[index % COLORS.length]);
107 plot.setRenderer(index, renderer);
108 }
109
110 public void addMeasure(Double value, Date date, Long serieId) {
111 seriesById.get(serieId).addOrUpdate(new Day(date), value);
112 }
113
114 public void addLabel(Date date, String label) throws ParseException {
115 addLabel(date, label, false);
116 }
117
118 public void addLabel(Date date, String label, boolean lower) throws ParseException {
119 Day d = new Day(date);
120 double millis = d.getFirstMillisecond();
121 Marker marker = new ValueMarker(millis);
122 marker.setLabel(label);
123 marker.setLabelAnchor(RectangleAnchor.TOP_RIGHT);
124 marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);
125 Color c = new Color(17, 40, 95);
126 marker.setLabelPaint(c);
127 marker.setPaint(c);
128 marker.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 3.0f, new float[]{5f, 5f, 5f, 5f}, 2.0f));
129 if (lower) {
130 marker.setLabelOffset(new RectangleInsets(18, 0, 0, 5));
131 }
132 plot.addDomainMarker(marker);
133 }
134
135 @Override
136 protected BufferedImage getChartImage() throws IOException {
137 JFreeChart chart = new JFreeChart(null, TextTitle.DEFAULT_FONT, plot, true);
138 configureChart(chart, displayLegend ? RectangleEdge.BOTTOM : null);
139 return super.getBufferedImage(chart);
140 }
141 }