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 }