Java tutorial
/* =============== * Eastwood Charts * =============== * * (C) Copyright 2007, 2008, by Object Refinery Limited. * * Project Info: http://www.jfree.org/eastwood/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Java is a trademark or registered trademark of Sun Microsystems, Inc. * in the United States and other countries.] * * ---------------- * ChartEngine.java * ---------------- * (C) Copyright 2008, by Object Refinery Limited. * * Original Author: David Gilbert (for Object Refinery Limited); * Contributors: Niklas Therning; * * Changes * ------- * 09-Jun-2008 : Version 1, code factored out of ChartServlet.java (DG); * 10-Jun-2008 : Added support for sparklines (cht='ls'), and values in * parameter maps are String[] not String (DG); * 12-Jun-2008 : Set label background to null, fixing bug 1872190 (DG); * 27-Jun-2008 : Added support for 'chdl' in bar charts, and also 'chdlp' - * see patch 2002341 by Niklas Therning (DG); * 27-Jun-2008 : Disable plot outlines - see patch 2003913 by Niklas * Therning (DG); * 30-Jun-2008 : Added almost full support for 'chg' in xy and bar charts (NT); * 01-Jul-2008 : Added new Eastwood tags 'ewd2' and 'ewtr' (DG); * 02-Jul-2008 : Removed unnecessary code in createBarChart() (NT); * 02-Jul-2008 : Added font parameter to buildChart() and made sure the * configured font is used for all titles and labels (NT); * 14-Jul-2008 : Added buildChart(Map) method for convenience (DG); * 14-Jul-2008 : Moved data parsing methods to DataUtilities.java (DG); * 14-Jul-2008 : Added support for 'chds' data scaling - see patch 2001599 * by Niklas Therning (DG); * 15-Jul-2008 : Added check for XYPlot in 'chls' to prevent * ClassCastException (DG); * 16-Jul-2008 : Added new bar charts with 3D effect (DG); * 16-Jul-2008 : Fixed gridlines (DG); * 18-Jul-2008 : Applied workaround in bug report 2001830 * by Niklas Therning (DG); * */ package org.jfree.eastwood; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Paint; import java.awt.Stroke; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.annotations.CategoryTextAnnotation; import org.jfree.chart.annotations.XYPointerAnnotation; import org.jfree.chart.axis.Axis; import org.jfree.chart.axis.AxisLocation; import org.jfree.chart.axis.CategoryAnchor; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.CategoryLabelPositions; import org.jfree.chart.entity.TickLabelEntity; import org.jfree.chart.labels.ItemLabelAnchor; import org.jfree.chart.labels.ItemLabelPosition; import org.jfree.chart.labels.PieSectionLabelGenerator; import org.jfree.chart.labels.StandardPieToolTipGenerator; import org.jfree.chart.plot.CategoryMarker; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.DatasetRenderingOrder; import org.jfree.chart.plot.IntervalMarker; import org.jfree.chart.plot.Marker; import org.jfree.chart.plot.PiePlot; import org.jfree.chart.plot.PiePlot3D; import org.jfree.chart.plot.Plot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.AbstractRenderer; import org.jfree.chart.renderer.category.*; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.title.LegendTitle; import org.jfree.chart.title.TextTitle; import org.jfree.chart.title.Title; import org.jfree.data.Range; import org.jfree.data.category.CategoryDataset; import org.jfree.data.general.PieDataset; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.Layer; import org.jfree.ui.RectangleEdge; import org.jfree.ui.RectangleInsets; import org.jfree.ui.TextAnchor; import org.jfree.util.SortOrder; /** * The chart engine contains the code that reads the chart parameters and * returns a corresponding <code>JFreeChart</code> instance. */ public class ChartEngine { /** * Creates and returns a new <code>JFreeChart</code> instance that * reflects the specified parameters (which should be equivalent to * a parameter map returned by HttpServletRequest.getParameterMap() for * a valid URI for the Google Chart API. * * @param params the parameters (<code>null</code> not permitted). * * @return A chart corresponding to the specification in the supplied * parameters. */ public static JFreeChart buildChart(Map params) { return buildChart(params, new Font("Dialog", Font.PLAIN, 12)); } /** * Creates and returns a new <code>JFreeChart</code> instance that * reflects the specified parameters (which should be equivalent to * a parameter map returned by HttpServletRequest.getParameterMap() for * a valid URI for the Google Chart API. * * @param params the parameters (<code>null</code> not permitted). * @param font the font to use to draw titles, labels and legends. * * @return A chart corresponding to the specification in the supplied * parameters. */ public static JFreeChart buildChart(Map params, Font font) { if (params == null) { throw new IllegalArgumentException("Null 'params' argument."); } JFreeChart chart = null; // *** CHART TYPE ** String[] chartType = (String[]) params.get("cht"); int dataType = -1; // 0 = PieDataset; 1 = XYDataset; 2 = special // pie charts: 'p' and 'p3' if (chartType[0].equals("p")) { chart = createPieChart(); dataType = 0; } else if (chartType[0].equals("p3")) { chart = createPieChart3D(); dataType = 0; } // line chart: 'lc' else if (chartType[0].equals("lc")) { chart = createLineChart(); dataType = 1; } // sparkline: 'ls' else if (chartType[0].equals("ls")) { chart = createSparklineChart(); dataType = 1; } // xy chart: 'lxy' else if (chartType[0].equals("lxy")) { chart = createLineChart(); dataType = 3; } // bar charts: 'bhs', 'bhg', 'bhs' and 'bhg' else if (chartType[0].equals("bhs")) { chart = createStackedBarChart(PlotOrientation.HORIZONTAL); dataType = 2; } else if (chartType[0].equals("bhg")) { chart = createBarChart(PlotOrientation.HORIZONTAL); dataType = 2; } else if (chartType[0].equals("bvs")) { chart = createStackedBarChart(PlotOrientation.VERTICAL); dataType = 2; } else if (chartType[0].equals("bvg")) { chart = createBarChart(PlotOrientation.VERTICAL); dataType = 2; } else if (chartType[0].equals("bhs3")) { chart = createStackedBarChart3D(PlotOrientation.HORIZONTAL); dataType = 2; } else if (chartType[0].equals("bhg3")) { chart = createBarChart3D(PlotOrientation.HORIZONTAL); dataType = 2; } else if (chartType[0].equals("bvs3")) { chart = createStackedBarChart3D(PlotOrientation.VERTICAL); dataType = 2; } else if (chartType[0].equals("bvg3")) { chart = createBarChart3D(PlotOrientation.VERTICAL); dataType = 2; } // scatter chart: 's' else if (chartType[0].equals("s")) { chart = createScatterChart(); dataType = 4; } else if (chartType[0].equals("v")) { throw new RuntimeException("Venn diagrams not implemented."); // TODO: fix this. } else { throw new RuntimeException("Unknown chart type: " + chartType[0]); } chart.getPlot().setOutlineVisible(false); // *** CHART AXES *** List axes = new java.util.ArrayList(); String[] axisStr = (String[]) params.get("chxt"); if (axisStr != null) { if (chart.getPlot() instanceof XYPlot) { XYPlot plot = (XYPlot) chart.getPlot(); processAxisStr(plot, axisStr[0], axes); } else if (chart.getPlot() instanceof CategoryPlot) { CategoryPlot plot = (CategoryPlot) chart.getPlot(); if (plot.getOrientation() == PlotOrientation.VERTICAL) { processAxisStrV(plot, axisStr[0], axes); } else { processAxisStrH(plot, axisStr[0], axes); } } } // *** AXIS RANGES *** String[] axisRangeStr = (String[]) params.get("chxr"); if (axisRangeStr != null) { String[] ranges = breakString(axisRangeStr[0], '|'); for (int i = 0; i < ranges.length; i++) { int comma1 = ranges[i].indexOf(','); int comma2 = ranges[i].indexOf(',', comma1 + 1); int axisIndex = Integer.parseInt(ranges[i].substring(0, comma1)); float lowerBound = Float.parseFloat(ranges[i].substring(comma1 + 1, comma2)); float upperBound = Float.parseFloat(ranges[i].substring(comma2 + 1)); Axis axis = (Axis) axes.get(axisIndex); if (axis instanceof GValueAxis) { GValueAxis gaxis = (GValueAxis) axis; gaxis.setLabelAxisStart(lowerBound); gaxis.setLabelAxisEnd(upperBound); } } } // *** AXIS LABELS *** String[] axisLabelStr = (String[]) params.get("chxl"); if (axisLabelStr != null) { Pattern p = Pattern.compile("\\d+:\\|"); Matcher m = p.matcher(axisLabelStr[0]); if (m.find()) { int keyStart = m.start(); int labelStart = m.end(); while (m.find(labelStart)) { String keyStr = axisLabelStr[0].substring(keyStart, labelStart - 2); int axisIndex = Integer.parseInt(keyStr); keyStart = m.start(); String labelStr = axisLabelStr[0].substring(labelStart, keyStart - 1); String[] labels = breakString(labelStr, '|'); GLabelledAxis axis = (GLabelledAxis) axes.get(axisIndex); axis.setTickLabels(Arrays.asList(labels)); labelStart = m.end(); } // process the final item String keyStr = axisLabelStr[0].substring(keyStart, labelStart - 2); String labelStr = axisLabelStr[0].substring(labelStart); int axisIndex = Integer.parseInt(keyStr); if (labelStr.endsWith("|")) { labelStr = labelStr.substring(0, labelStr.length() - 1); } String[] labels = breakString(labelStr, '|'); GLabelledAxis axis = (GLabelledAxis) axes.get(axisIndex); axis.setTickLabels(Arrays.asList(labels)); } else { throw new RuntimeException("No matching pattern!"); } } // ** EXPLICIT AXIS LABEL POSITIONS String[] axisPositionStr = (String[]) params.get("chxp"); if (axisPositionStr != null) { String[] positions = breakString(axisPositionStr[0], '|'); for (int i = 0; i < positions.length; i++) { int c1 = positions[i].indexOf(','); int axisIndex = Integer.parseInt(positions[i].substring(0, c1)); String remainingStr = positions[i].substring(c1 + 1); String[] valueStr = breakString(remainingStr, ','); List tickValues = new java.util.ArrayList(valueStr.length); Axis axis = (Axis) axes.get(axisIndex); if (axis instanceof GValueAxis) { GValueAxis gaxis = (GValueAxis) axes.get(axisIndex); for (int j = 0; j < valueStr.length; j++) { float pos = Float.parseFloat(valueStr[j]); tickValues.add(new Float(pos)); } gaxis.setTickLabelPositions(tickValues); } // FIXME: what about a CategoryAxis? } } // *** CHART TITLE *** String[] titleStr = (String[]) params.get("chtt"); if (titleStr != null) { // process the title String[] s = breakString(titleStr[0], '|'); for (int i = 0; i < s.length; i++) { TextTitle t = new TextTitle(s[i].replace('+', ' ')); t.setPaint(Color.darkGray); // Google seems to use 14pt fonts for titles and 12pt fonts for // all other text. Make sure this relationship remains. t.setFont(font.deriveFont(font.getSize2D() * 14f / 12f)); chart.addSubtitle(t); } // and the font and colour String[] fontStr = (String[]) params.get("chts"); if (fontStr != null) { int c1 = fontStr[0].indexOf(','); String colorStr = null; String fontSizeStr = null; if (c1 != -1) { colorStr = fontStr[0].substring(0, c1); fontSizeStr = fontStr[0].substring(c1 + 1); } else { colorStr = fontStr[0]; } Color color = parseColor(colorStr); int size = 12; if (fontSizeStr != null) { size = Integer.parseInt(fontSizeStr); } for (int i = 0; i < chart.getSubtitleCount(); i++) { Title t = chart.getSubtitle(i); if (t instanceof TextTitle) { TextTitle tt = (TextTitle) t; tt.setPaint(color); tt.setFont(font.deriveFont((float) size)); } } } } // *** CHART DATA *** String[] dataStr = (String[]) params.get("chd"); String scalingStr = null; if (dataStr.length > 0 && dataStr[0].startsWith("t:")) { // Only look at chds when text encoding is used String[] chds = (String[]) params.get("chds"); if (chds != null && chds.length > 0) { scalingStr = chds[0]; } } // we'll also process an optional second dataset that is provided as // an Eastwood extension...this isn't part of the Google Chart API String[] d2Str = (String[]) params.get("ewd2"); // 'p' and 'p3' - create PieDataset if (dataType == 0) { PieDataset dataset = DataUtilities.parsePieDataset(dataStr[0], scalingStr); PiePlot plot = (PiePlot) chart.getPlot(); plot.setDataset(dataset); // ignore d2Str as there is currently no need for a second pie // dataset. } // 'lc' - create XYDataset else if (dataType == 1) { XYPlot plot = (XYPlot) chart.getPlot(); XYDataset dataset = DataUtilities.parseXYDataset(dataStr[0], scalingStr); plot.setDataset(dataset); if (d2Str != null) { // an Eastwood extension XYDataset d2 = DataUtilities.parseXYDataset(d2Str[0], scalingStr); plot.setDataset(1, d2); } } // 'bhs', 'bhg', 'bvs', 'bvg' else if (dataType == 2) { CategoryPlot plot = (CategoryPlot) chart.getPlot(); CategoryDataset dataset = DataUtilities.parseCategoryDataset(dataStr[0], scalingStr); plot.setDataset(dataset); if (d2Str != null) { // an Eastwood extension CategoryDataset d2 = DataUtilities.parseCategoryDataset(d2Str[0], scalingStr); plot.setDataset(1, d2); } } // 'lxy' else if (dataType == 3) { XYPlot plot = (XYPlot) chart.getPlot(); XYDataset dataset = DataUtilities.parseXYDataset2(dataStr[0], scalingStr); plot.setDataset(dataset); if (d2Str != null) { // an Eastwood extension XYDataset d2 = DataUtilities.parseXYDataset2(d2Str[0], scalingStr); plot.setDataset(1, d2); } } else if (dataType == 4) { XYPlot plot = (XYPlot) chart.getPlot(); XYSeriesCollection dataset = DataUtilities.parseScatterDataset(dataStr[0], scalingStr); if (dataset.getSeriesCount() > 1) { dataset.removeSeries(1); } plot.setDataset(dataset); if (d2Str != null) { // an Eastwood extension XYDataset d2 = DataUtilities.parseXYDataset2(d2Str[0], scalingStr); plot.setDataset(1, d2); } } if (chart.getPlot() instanceof XYPlot) { XYPlot plot = (XYPlot) chart.getPlot(); plot.getDomainAxis().setLabelFont(font); plot.getDomainAxis().setTickLabelFont(font); plot.getRangeAxis().setLabelFont(font); plot.getRangeAxis().setTickLabelFont(font); } else if (chart.getPlot() instanceof CategoryPlot) { CategoryPlot plot = (CategoryPlot) chart.getPlot(); plot.getDomainAxis().setLabelFont(font); plot.getDomainAxis().setTickLabelFont(font); plot.getRangeAxis().setLabelFont(font); plot.getRangeAxis().setTickLabelFont(font); } // *** CHART COLOURS *** String[] colorStr = (String[]) params.get("chco"); if (colorStr != null) { Color[] colors = parseColors(colorStr[0]); if (dataType == 0) { PiePlot plot = (PiePlot) chart.getPlot(); applyColorsToPiePlot(plot, colors); } else { AbstractRenderer renderer = null; if (chart.getPlot() instanceof CategoryPlot) { CategoryPlot plot = (CategoryPlot) chart.getPlot(); renderer = (AbstractRenderer) plot.getRenderer(); renderer.setBasePaint(colors[0]); } else if (chart.getPlot() instanceof XYPlot) { XYPlot plot = (XYPlot) chart.getPlot(); renderer = (AbstractRenderer) plot.getRenderer(); renderer.setBasePaint(colors[colors.length - 1]); } for (int i = 0; i < colors.length; i++) { renderer.setSeriesPaint(i, colors[i]); } } } else { Plot plot = chart.getPlot(); if (plot instanceof PiePlot) { applyColorsToPiePlot((PiePlot) chart.getPlot(), new Color[] { new Color(255, 153, 0) }); } } // *** CHART LINE STYLES *** String[] lineStr = (String[]) params.get("chls"); if (lineStr != null && chart.getPlot() instanceof XYPlot) { Stroke[] strokes = parseLineStyles(lineStr[0]); XYPlot plot = (XYPlot) chart.getPlot(); XYItemRenderer renderer = plot.getRenderer(); for (int i = 0; i < strokes.length; i++) { renderer.setSeriesStroke(i, strokes[i]); } renderer.setBaseStroke(strokes[strokes.length - 1]); } // *** CHART GRID LINES if (dataType != 0) { String[] gridStr = (String[]) params.get("chg"); if (gridStr != null) { processGridLinesSpec(gridStr[0], chart); } } // *** CHART LABELS if (dataType == 0) { // pie chart String[] labelStr = (String[]) params.get("chl"); if (labelStr != null) { String[] s = breakString(labelStr[0], '|'); List labels = Arrays.asList(s); PiePlot plot = (PiePlot) chart.getPlot(); if (labels.size() > 0) { plot.setLabelGenerator(new GPieSectionLabelGenerator(labels)); plot.setLabelFont(font); plot.setLabelPaint(Color.darkGray); } } } String[] legendStr = (String[]) params.get("chdl"); if (legendStr != null) { // process the title String[] s = breakString(legendStr[0], '|'); List labels = Arrays.asList(s); if (labels.size() > 0) { Plot p = chart.getPlot(); if (p instanceof CategoryPlot) { CategoryPlot plot = (CategoryPlot) chart.getPlot(); BarRenderer renderer = (BarRenderer) plot.getRenderer(); renderer.setLegendItemLabelGenerator(new GSeriesLabelGenerator(labels)); renderer.setBaseSeriesVisibleInLegend(false); for (int i = 0; i < labels.size(); i++) { renderer.setSeriesVisibleInLegend(i, Boolean.TRUE); } } else if (p instanceof XYPlot) { XYPlot plot = (XYPlot) chart.getPlot(); XYItemRenderer renderer = plot.getRenderer(); renderer.setLegendItemLabelGenerator(new GSeriesLabelGenerator(labels)); renderer.setBaseSeriesVisibleInLegend(false); for (int i = 0; i < labels.size(); i++) { renderer.setSeriesVisibleInLegend(i, Boolean.TRUE); } } else if (p instanceof PiePlot) { PiePlot plot = (PiePlot) chart.getPlot(); plot.setLegendLabelGenerator(new GPieSectionLabelGenerator(labels)); } LegendTitle legend = new LegendTitle(chart.getPlot()); RectangleEdge pos = RectangleEdge.RIGHT; String[] chdlp = (String[]) params.get("chdlp"); if (chdlp != null) { if ("b".equals(chdlp[0])) { pos = RectangleEdge.BOTTOM; } else if ("t".equals(chdlp[0])) { pos = RectangleEdge.TOP; } else if ("l".equals(chdlp[0])) { pos = RectangleEdge.LEFT; } } legend.setPosition(pos); legend.setItemFont(font); legend.setItemPaint(Color.darkGray); chart.addSubtitle(legend); } } // *** CHART MARKERS *** String[] markerStr = (String[]) params.get("chm"); if (markerStr != null) { String[] markers = breakString(markerStr[0], '|'); for (int i = 0; i < markers.length; i++) { addMarker(markers[i], chart); } } // *** CHART FILL ***/ String[] fillStr = (String[]) params.get("chf"); if (fillStr != null) { // process the 1 or 2 fill specs int i = fillStr[0].indexOf('|'); if (i == -1) { processFillSpec(fillStr[0], chart); } else { String fs1 = fillStr[0].substring(0, i); String fs2 = fillStr[0].substring(i + 1); processFillSpec(fs1, chart); processFillSpec(fs2, chart); } } // process the 'ewtr' tag, if present processEWTR(params, chart); return chart; } /** * The 'ewtr' tag is an Eastwood extension that draws a trend line over a * chart, using data that has been added to a secondary dataset using the * 'ewd2' tag. * * @param params the chart parameters; * @param chart the chart under construction (will be updated by this * method if necessary). */ public static void processEWTR(Map params, JFreeChart chart) { // the 'ewtr' arguments are: // - <seriesIndex> : the index of the series in the secondary dataset; // - <colour> : the colour; // - <lineThickness> : the line thickness; String[] ewtrStr = (String[]) params.get("ewtr"); if (ewtrStr != null) { String[] atts = ewtrStr[0].split(","); int series = Integer.parseInt(atts[0]); Color color = parseColor(atts[1]); float lineWidth = Float.parseFloat(atts[2]); Plot plot = chart.getPlot(); if (plot instanceof CategoryPlot) { CategoryPlot cp = (CategoryPlot) plot; if (cp.getDataset(1) != null) { LineAndShapeRenderer r = new LineAndShapeRenderer(true, false); r.setBaseSeriesVisible(false); r.setSeriesVisible(series, Boolean.TRUE); r.setSeriesPaint(series, color); r.setSeriesStroke(series, new BasicStroke(lineWidth)); cp.setRenderer(1, r); cp.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); } } else if (plot instanceof XYPlot) { XYPlot xp = (XYPlot) plot; if (xp.getDataset(1) != null) { XYLineAndShapeRenderer r = new XYLineAndShapeRenderer(true, false); r.setBaseSeriesVisible(false); r.setSeriesVisible(series, Boolean.TRUE); r.setSeriesPaint(series, color); r.setSeriesStroke(series, new BasicStroke(lineWidth)); xp.setRenderer(1, r); xp.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD); } } } } /** * Creates a pie chart. * * @return A pie chart. */ private static JFreeChart createPieChart() { JFreeChart chart = ChartFactory.createPieChart(null, null, false, true, false); chart.setBackgroundPaint(Color.white); PiePlot plot = (PiePlot) chart.getPlot(); plot.setBackgroundPaint(null); plot.setInsets(RectangleInsets.ZERO_INSETS); plot.setInteriorGap(0.06); plot.setStartAngle(0.0); plot.setLabelGenerator(null); plot.setBaseSectionOutlinePaint(Color.white); plot.setBaseSectionOutlineStroke(new BasicStroke(1.2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); plot.setOutlineVisible(false); plot.setLabelBackgroundPaint(null); plot.setLabelOutlinePaint(null); plot.setLabelShadowPaint(null); plot.setLabelPadding(RectangleInsets.ZERO_INSETS); plot.setLabelFont(new Font("Dialog", Font.PLAIN, 12)); plot.setLabelPaint(Color.darkGray); plot.setToolTipGenerator(new StandardPieToolTipGenerator("{2}")); return chart; } /** * Creates a pie chart with 3D effect. * * @return A pie chart. */ private static JFreeChart createPieChart3D() { JFreeChart chart = ChartFactory.createPieChart3D(null, null, false, true, false); chart.setBackgroundPaint(Color.white); chart.setBorderPaint(Color.white); PiePlot3D plot = (PiePlot3D) chart.getPlot(); plot.setInsets(RectangleInsets.ZERO_INSETS); plot.setDarkerSides(true); plot.setBaseSectionOutlinePaint(new Color(0, 0, 0, 0)); plot.setStartAngle(0.0); plot.setInteriorGap(0.10); plot.setLabelGenerator(null); plot.setOutlineVisible(false); plot.setLabelBackgroundPaint(Color.white); plot.setLabelOutlinePaint(null); plot.setLabelShadowPaint(null); plot.setLabelPadding(RectangleInsets.ZERO_INSETS); plot.setLabelFont(new Font("Dialog", Font.PLAIN, 12)); plot.setLabelPaint(Color.darkGray); plot.setToolTipGenerator(new StandardPieToolTipGenerator("{2}")); return chart; } /** * Creates a line chart. * * @return A line chart. */ private static JFreeChart createLineChart() { GXYPlot plot = new GXYPlot(); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(); renderer.setBaseShapesVisible(false); plot.setRenderer(renderer); JFreeChart chart = new JFreeChart(plot); chart.removeLegend(); chart.setBackgroundPaint(Color.white); renderer.setBasePaint(new Color(0xFF9900)); renderer.setBaseStroke(new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); renderer.setAutoPopulateSeriesPaint(false); renderer.setItemLabelsVisible(true); renderer.setItemLabelGenerator(new GXYPlot.LabelGenerator()); renderer.setItemLabelPaint(new Color(0x333435)); renderer.setPositiveItemLabelPosition( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT)); GValueAxis xAxis = new GValueAxis(); xAxis.setTickLabelsVisible(false); xAxis.setTickMarksVisible(false); plot.setDomainAxis(xAxis); GValueAxis yAxis = new GValueAxis(); yAxis.setTickLabelsVisible(false); yAxis.setTickMarksVisible(false); plot.setRangeAxis(yAxis); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); return chart; } /** * Creates a sparkline chart. * * @return A sparkline chart. */ private static JFreeChart createSparklineChart() { GXYPlot plot = new GXYPlot(); plot.setInsets(RectangleInsets.ZERO_INSETS); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(); renderer.setBaseShapesVisible(false); plot.setRenderer(renderer); JFreeChart chart = new JFreeChart(plot); chart.setPadding(RectangleInsets.ZERO_INSETS); chart.removeLegend(); chart.setBackgroundPaint(Color.white); renderer.setBasePaint(new Color(0xFF9900)); renderer.setBaseStroke(new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); renderer.setAutoPopulateSeriesPaint(false); GValueAxis xAxis = new GValueAxis(); xAxis.setVisible(false); plot.setDomainAxis(xAxis); GValueAxis yAxis = new GValueAxis(); yAxis.setVisible(false); plot.setRangeAxis(yAxis); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); return chart; } /** * Creates a bar chart with the specified orientation and using the * specified renderer. * * @param orientation the plot orientation. * @param renderer the renderer. * * @return A bar chart. */ private static JFreeChart createBarChart(PlotOrientation orientation, BarRenderer renderer) { GCategoryPlot plot = new GCategoryPlot(); plot.setOrientation(orientation); JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false); chart.setBackgroundPaint(Color.white); plot.setBackgroundPaint(null); plot.setRenderer(renderer); StandardBarPainter bp = new StandardBarPainter(); renderer.setBarPainter(bp); renderer.setShadowVisible(false); renderer.setBasePaint(new Color(0xFFCC33)); renderer.setAutoPopulateSeriesPaint(false); renderer.setItemLabelsVisible(true); renderer.setItemLabelGenerator(new GCategoryPlot.LabelGenerator()); renderer.setItemLabelPaint(new Color(0x333435)); renderer.setDrawBarOutline(false); renderer.setItemMargin(0.07); if (orientation == PlotOrientation.HORIZONTAL) { renderer.setPositiveItemLabelPosition( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT)); renderer.setPositiveItemLabelPositionFallback( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_RIGHT)); } else { renderer.setPositiveItemLabelPosition( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER)); renderer.setPositiveItemLabelPositionFallback( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.TOP_CENTER)); } GCategoryAxis xAxis = new GCategoryAxis(); xAxis.setAxisLineVisible(true); xAxis.setTickLabelsVisible(false); xAxis.setMaximumCategoryLabelLines(5); plot.setDomainAxis(xAxis); GValueAxis yAxis = new GValueAxis(); yAxis.setAxisLineVisible(true); yAxis.setTickLabelsVisible(false); yAxis.setTickMarksVisible(false); plot.setRangeAxis(yAxis); plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); return chart; } /** * Creates a bar chart with the specified orientation. * * @param orientation the plot orientation. * * @return A bar chart. */ private static JFreeChart createBarChart(PlotOrientation orientation) { return createBarChart(orientation, new BarRenderer()); } /** * Creates a stacked bar chart with the specified orientation. * * @param orientation the orientation. * * @return A stacked bar chart. */ private static JFreeChart createStackedBarChart(PlotOrientation orientation) { return createBarChart(orientation, new StackedBarRenderer()); } /** * Creates a bar chart with the specified orientation and using the * specified renderer. * * @param orientation the plot orientation. * @param renderer the renderer. * * @return A bar chart. */ private static JFreeChart createBarChart3D(PlotOrientation orientation, BarRenderer renderer) { GCategoryPlot plot = new GCategoryPlot(); plot.setOrientation(orientation); if (orientation.equals(PlotOrientation.HORIZONTAL)) { plot.setColumnRenderingOrder(SortOrder.DESCENDING); } JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false); chart.setBackgroundPaint(Color.white); plot.setBackgroundPaint(null); plot.setRenderer(renderer); renderer.setBasePaint(new Color(0xFFCC33)); renderer.setAutoPopulateSeriesPaint(false); renderer.setBasePaint(new Color(0xFFCC33)); renderer.setAutoPopulateSeriesPaint(false); renderer.setItemLabelsVisible(true); renderer.setItemLabelGenerator(new GCategoryPlot.LabelGenerator()); renderer.setItemLabelPaint(new Color(0x333435)); if (orientation == PlotOrientation.HORIZONTAL) { renderer.setPositiveItemLabelPosition( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT)); renderer.setPositiveItemLabelPositionFallback( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_RIGHT)); } else { renderer.setPositiveItemLabelPosition( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER)); renderer.setPositiveItemLabelPositionFallback( new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.TOP_CENTER)); } GCategoryAxis3D xAxis = new GCategoryAxis3D(); xAxis.setAxisLineVisible(true); xAxis.setTickLabelsVisible(false); xAxis.setMaximumCategoryLabelLines(5); plot.setDomainAxis(xAxis); GValueAxis3D yAxis = new GValueAxis3D(); yAxis.setAxisLineVisible(true); yAxis.setTickLabelsVisible(false); yAxis.setTickMarksVisible(false); plot.setRangeAxis(yAxis); plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); return chart; } /** * Creates a bar chart with the specified orientation. * * @param orientation the plot orientation. * * @return A bar chart. */ private static JFreeChart createBarChart3D(PlotOrientation orientation) { return createBarChart3D(orientation, new BarRenderer3D()); } /** * Creates a stacked bar chart with the specified orientation. * * @param orientation the orientation. * * @return A stacked bar chart. */ private static JFreeChart createStackedBarChart3D(PlotOrientation orientation) { return createBarChart3D(orientation, new StackedBarRenderer3D()); } /** * Creates a scatter chart. * * @return A scatter chart. */ private static JFreeChart createScatterChart() { JFreeChart chart = ChartFactory.createScatterPlot(null, null, null, null, PlotOrientation.VERTICAL, false, false, false); chart.setBackgroundPaint(Color.white); XYPlot plot = (XYPlot) chart.getPlot(); plot.setBackgroundPaint(null); plot.setOutlinePaint(null); XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer(); renderer.setBasePaint(new Color(0x76A4FB)); renderer.setAutoPopulateSeriesPaint(false); GValueAxis xAxis = new GValueAxis(); xAxis.setTickLabelsVisible(false); xAxis.setTickMarksVisible(false); plot.setDomainAxis(xAxis); GValueAxis yAxis = new GValueAxis(); yAxis.setTickLabelsVisible(false); yAxis.setTickMarksVisible(false); plot.setRangeAxis(yAxis); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); return chart; } /** * Processes a string that indicates the axes that should be visible on * the plot. * * @param plot the plot. * @param axisStr the axis specification. * @param axes a list that will be populated with any axes added to the * plot. */ private static void processAxisStr(XYPlot plot, String axisStr, List axes) { int xAxisCount = 0; int yAxisCount = 0; for (int i = 0; i < axisStr.length(); i++) { char c = axisStr.charAt(i); if (c == 'x') { if (xAxisCount == 0) { Axis xAxis = plot.getDomainAxis(); xAxis.setTickMarksVisible(true); xAxis.setTickLabelsVisible(true); axes.add(xAxis); xAxisCount++; } else { GValueAxis axis = new GValueAxis(); axis.setAxisLineVisible(false); plot.setDomainAxis(xAxisCount, axis); plot.setDomainAxisLocation(xAxisCount, AxisLocation.BOTTOM_OR_LEFT); axes.add(axis); xAxisCount++; } } else if (c == 'y') { if (yAxisCount == 0) { Axis yAxis = plot.getRangeAxis(); yAxis.setTickMarksVisible(true); yAxis.setTickLabelsVisible(true); axes.add(yAxis); yAxisCount++; } else { GValueAxis axis = new GValueAxis(); axis.setAxisLineVisible(false); plot.setRangeAxis(yAxisCount, axis); plot.setRangeAxisLocation(yAxisCount, AxisLocation.BOTTOM_OR_LEFT); axes.add(axis); yAxisCount++; } } else if (c == 'r') { GValueAxis axis = new GValueAxis(); plot.setRangeAxis(yAxisCount, axis); plot.setRangeAxisLocation(yAxisCount, AxisLocation.BOTTOM_OR_RIGHT); axes.add(axis); yAxisCount++; } else if (c == 't') { GValueAxis axis = new GValueAxis(); plot.setDomainAxis(xAxisCount, axis); plot.setDomainAxisLocation(xAxisCount, AxisLocation.TOP_OR_LEFT); axes.add(axis); xAxisCount++; } else if (c == ',') { // nothing to do } else { throw new RuntimeException("Bad character " + c); } } } /** * Processes a string that indicates the axes that should be visible on * the plot. * * @param plot the plot. * @param axisStr the axis specification. * @param axes a list that will be populated with any axes added to the * plot. */ private static void processAxisStrV(CategoryPlot plot, String axisStr, List axes) { int xAxisCount = 0; int yAxisCount = 0; for (int i = 0; i < axisStr.length(); i++) { char c = axisStr.charAt(i); if (c == 'x') { if (xAxisCount == 0) { CategoryAxis xAxis = plot.getDomainAxis(); xAxis.setTickLabelsVisible(true); axes.add(xAxis); xAxisCount++; } else { GCategoryAxis axis = new GCategoryAxis(); axis.setAxisLineVisible(false); plot.setDomainAxis(xAxisCount, axis); plot.setDomainAxisLocation(xAxisCount, AxisLocation.BOTTOM_OR_LEFT); axes.add(axis); xAxisCount++; } } else if (c == 'y') { if (yAxisCount == 0) { Axis yAxis = plot.getRangeAxis(); yAxis.setTickLabelsVisible(true); yAxis.setTickMarksVisible(true); axes.add(yAxis); yAxisCount++; } else { GValueAxis axis = new GValueAxis(); axis.setAxisLineVisible(false); plot.setRangeAxis(yAxisCount, axis); plot.setRangeAxisLocation(yAxisCount, AxisLocation.BOTTOM_OR_LEFT); axes.add(axis); yAxisCount++; } } else if (c == 'r') { GValueAxis axis = new GValueAxis(); plot.setRangeAxis(yAxisCount, axis); plot.setRangeAxisLocation(yAxisCount, AxisLocation.BOTTOM_OR_RIGHT); axes.add(axis); yAxisCount++; } else if (c == 't') { GCategoryAxis axis = new GCategoryAxis(); axis.setAxisLineVisible(false); plot.setDomainAxis(xAxisCount, axis); plot.setDomainAxisLocation(xAxisCount, AxisLocation.TOP_OR_LEFT); axes.add(axis); xAxisCount++; } else if (c == ',') { // nothing to do } else { throw new RuntimeException("Bad character " + c); } } } /** * Processes a string that indicates the axes that should be visible on * the plot. * * @param plot the plot. * @param axisStr the axis specification. * @param axes a list that will be populated with any axes added to the * plot. */ private static void processAxisStrH(CategoryPlot plot, String axisStr, List axes) { int xAxisCount = 0; int yAxisCount = 0; for (int i = 0; i < axisStr.length(); i++) { char c = axisStr.charAt(i); if (c == 'y') { if (yAxisCount == 0) { CategoryAxis axis = plot.getDomainAxis(); axis.setTickLabelsVisible(true); axes.add(axis); yAxisCount++; } else { GCategoryAxis axis = new GCategoryAxis(); axis.setAxisLineVisible(false); plot.setDomainAxis(yAxisCount, axis); plot.setDomainAxisLocation(xAxisCount, AxisLocation.BOTTOM_OR_LEFT); axes.add(axis); yAxisCount++; } } else if (c == 'x') { if (xAxisCount == 0) { Axis axis = plot.getRangeAxis(); axis.setTickLabelsVisible(true); axis.setTickMarksVisible(true); axes.add(axis); xAxisCount++; } else { GValueAxis axis = new GValueAxis(); axis.setAxisLineVisible(false); plot.setRangeAxis(xAxisCount, axis); plot.setRangeAxisLocation(xAxisCount, AxisLocation.BOTTOM_OR_LEFT); axes.add(axis); xAxisCount++; } } else if (c == 't') { GValueAxis axis = new GValueAxis(); plot.setRangeAxis(xAxisCount, axis); plot.setRangeAxisLocation(yAxisCount, AxisLocation.TOP_OR_LEFT); axes.add(axis); xAxisCount++; } else if (c == 'r') { GCategoryAxis axis = new GCategoryAxis(); plot.setDomainAxis(yAxisCount, axis); plot.setDomainAxisLocation(xAxisCount, AxisLocation.BOTTOM_OR_RIGHT); axes.add(axis); yAxisCount++; } else if (c == ',') { // nothing to do } else { throw new RuntimeException("Bad character " + c); } } } /** * A utility method that splits the supplied string at every occurrence of * the specified separator. * * @param text the text (<code>null</code> not permitted). * @param separator the separator character. * * @return An array of strings. */ private static String[] breakString(String text, char separator) { if (text == null) { throw new IllegalArgumentException("Null 'text' argument."); } List temp = new java.util.ArrayList(); String current = text; int i = current.indexOf(separator); while (i != -1) { String line = current.substring(0, i); temp.add(line); current = current.substring(i + 1); i = current.indexOf(separator); } temp.add(current); String[] result = new String[temp.size()]; for (int j = 0; j < temp.size(); j++) { result[j] = (String) temp.get(j); } return result; } /** * Creates a color from the supplied string, which should be in RRGGBB * format, or RRGGBBAA. * * @param text the text encoding (<code>null</code> not permitted). * * @return A color. */ private static Color parseColor(String text) { if (text == null) { throw new IllegalArgumentException("Null 'text' argument (in parseColor(String))."); } return Color.decode("0x" + text); } /** * Parses a string containing a comma-separated list of color values (in * the format RRGGBB or RRGGBBAA). * * @param text the text (<code>null</code> not permitted). * * @return The colors. */ private static Color[] parseColors(String text) { if (text == null) { throw new IllegalArgumentException("Null 'text' argument (in parseColors(String))."); } String[] codes = breakString(text, ','); Color[] result = new Color[codes.length]; for (int i = 0; i < codes.length; i++) { if (codes[i].length() > 0) { String code = breakString(codes[i], '|')[0]; result[i] = Color.decode("0x" + code); } else { result[i] = Color.black; } } return result; } private static void applyColorsToPiePlot(PiePlot plot, Color[] colors) { if (colors.length == 1) { Color c = colors[0]; colors = new Color[2]; colors[0] = c; colors[1] = new Color(255 - ((255 - c.getRed()) / 5), 255 - ((255 - c.getGreen()) / 5), 255 - ((255 - c.getBlue()) / 5)); } PieDataset dataset = plot.getDataset(); int sectionCount = dataset.getItemCount(); if (colors.length < sectionCount) { // we need to interpolate some // colors for (int i = 0; i < colors.length - 1; i++) { Color c1 = colors[i]; Color c2 = colors[i + 1]; int s1 = sectionIndexForColor(i, colors.length, sectionCount); int s2 = sectionIndexForColor(i + 1, colors.length, sectionCount); for (int s = s1; s <= s2; s++) { Color c = interpolatedColor(c1, c2, s - s1, s2 - s1); plot.setSectionPaint(dataset.getKey(s), c); } } } else { for (int i = 0; i < sectionCount; i++) { plot.setSectionPaint(dataset.getKey(i), colors[i]); } } } private static int sectionIndexForColor(int item, int itemCount, int sectionCount) { return (int) (Math.min(sectionCount - 1, item * sectionCount / (itemCount - 1.0))); } private static Color interpolatedColor(Color c1, Color c2, int index, int range) { if (index == 0) { return c1; } if (index == range) { return c2; } double fraction = (index + 0.0) / range; int r1 = c1.getRed(); int g1 = c1.getGreen(); int b1 = c1.getBlue(); int r2 = c2.getRed(); int g2 = c2.getGreen(); int b2 = c2.getBlue(); return new Color((int) (r1 + fraction * (r2 - r1)), (int) (g1 + fraction * (g2 - g1)), (int) (b1 + fraction * (b2 - b1))); } /** * Parses a string containing a sequence of line style specifications, * returning an array of <code>Stroke</code> objects. * * @param text the line styles. * * @return The strokes representing the line styles. */ private static Stroke[] parseLineStyles(String text) { if (text == null) { throw new IllegalArgumentException("Null 'text' argument (in parseStrokes(String))."); } String[] codes = breakString(text, '|'); Stroke[] result = new BasicStroke[codes.length]; for (int i = 0; i < codes.length; i++) { float width = 1.0f; float lineRun = 1.0f; float gapRun = 0.0f; int pos = codes[i].indexOf(','); if (pos == -1) { width = Float.parseFloat(codes[i]); } else { String widthStr = codes[i].substring(0, pos); width = Float.parseFloat(widthStr); String remaining = codes[i].substring(pos + 1); pos = remaining.indexOf(','); if (pos == -1) { lineRun = Float.parseFloat(remaining); gapRun = lineRun; } else { String s1 = remaining.substring(0, pos); lineRun = Float.parseFloat(s1); String s2 = remaining.substring(pos + 1); gapRun = Float.parseFloat(s2); } } if (gapRun <= 0.0f) { result[i] = new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); } else { result[i] = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 5.0f, new float[] { lineRun, gapRun }, 0.0f); } } return result; } /** * Adds a marker to the chart. * * @param markerStr the string encoding of the marker. * @param chart the chart to apply the marker to. */ private static void addMarker(String markerStr, JFreeChart chart) { String[] args = breakString(markerStr, ','); Plot p = chart.getPlot(); Color c = parseColor(args[1]); if (args[0].startsWith("t")) { String text = args[0].substring(1); int dataset = Integer.parseInt(args[2]); int datapoint = Integer.parseInt(args[3]); float fontsize = Float.parseFloat(args[4]); if (p instanceof CategoryPlot) { CategoryPlot cp = (CategoryPlot) p; CategoryItemRenderer r = cp.getRenderer(); GCategoryPlot.LabelGenerator label = (GCategoryPlot.LabelGenerator) r.getItemLabelGenerator(dataset, datapoint); label.setLabel(dataset, datapoint, text); } else if (p instanceof XYPlot) { XYPlot xyp = (XYPlot) p; XYItemRenderer r = xyp.getRenderer(); ((GXYPlot.LabelGenerator) r.getItemLabelGenerator(dataset, datapoint)).setLabel(dataset, datapoint, text); //XYDataset d = xyp.getDataset(); //XYPointerAnnotation a = new XYPointerAnnotation(text, d.getXValue(dataset, datapoint), d.getYValue(dataset, datapoint), Math.random()-2); //xyp.addAnnotation(a); } } else if ("r".equals(args[0])) { // add a range marker float f0 = Float.parseFloat(args[3]); float f1 = Float.parseFloat(args[4]); if (p instanceof CategoryPlot) { CategoryPlot cp = (CategoryPlot) p; Range yRange = cp.getRangeAxis().getRange(); double r0 = yRange.getLowerBound(); double rl = yRange.getLength(); IntervalMarker m = new IntervalMarker(r0 + Math.min(f0, f1) * rl, r0 + Math.max(f0, f1) * rl); m.setPaint(c); cp.addRangeMarker(m, Layer.BACKGROUND); } else if (p instanceof XYPlot) { XYPlot cp = (XYPlot) p; Range yRange = cp.getRangeAxis().getRange(); double r0 = yRange.getLowerBound(); double rl = yRange.getLength(); IntervalMarker m = new IntervalMarker(r0 + Math.min(f0, f1) * rl, r0 + Math.max(f0, f1) * rl); m.setPaint(c); cp.addRangeMarker(m, Layer.BACKGROUND); } } else if ("R".equals(args[0])) { // add a domain marker float f0 = Float.parseFloat(args[3]); float f1 = Float.parseFloat(args[4]); if (p instanceof XYPlot) { XYPlot xyp = (XYPlot) p; Range yRange = xyp.getRangeAxis().getRange(); double r0 = yRange.getLowerBound(); double rl = yRange.getLength(); IntervalMarker m = new IntervalMarker(r0 + Math.min(f0, f1) * rl, r0 + Math.max(f0, f1) * rl); m.setPaint(c); xyp.addDomainMarker(m, Layer.BACKGROUND); } } } /** * Process the string which contains an encoding for the chart background * fill, and apply it to the chart. * * @param spec the fill specification. * @param chart the chart. */ private static void processFillSpec(String spec, JFreeChart chart) { if (spec.startsWith("bg")) { // do the chart background spec = spec.substring(3); if (spec.startsWith("s")) { spec = spec.substring(2); Color c = parseColor(spec); chart.setBackgroundPaint(c); } else if (spec.startsWith("lg")) { spec = spec.substring(3); String[] args = breakString(spec, ','); int angle = Integer.parseInt(args[0]); Color c0 = parseColor(args[1]); float f0 = Float.parseFloat(args[2]); Color c1 = parseColor(args[3]); float f1 = Float.parseFloat(args[4]); if (chart.getPlot() instanceof GXYPlot) { GXYPlot gxyplot = (GXYPlot) chart.getPlot(); gxyplot.setF0(f0); gxyplot.setF1(f1); gxyplot.setAngle(Math.PI / 180.0 * angle); gxyplot.setBackgroundPaint(new GradientPaint(0.0f, 0.0f, c0, 0.0f, 0.0f, c1)); } } } else if (spec.startsWith("c")) { // do the plot background spec = spec.substring(2); if (spec.startsWith("s")) { spec = spec.substring(2); Color c = parseColor(spec); chart.getPlot().setBackgroundPaint(c); } else if (spec.startsWith("lg")) { spec = spec.substring(3); String[] args = breakString(spec, ','); int angle = Integer.parseInt(args[0]); Color c0 = parseColor(args[1]); float f0 = Float.parseFloat(args[2]); Color c1 = parseColor(args[3]); float f1 = Float.parseFloat(args[4]); if (chart.getPlot() instanceof GXYPlot) { GXYPlot gxyplot = (GXYPlot) chart.getPlot(); gxyplot.setF0(f0); gxyplot.setF1(f1); gxyplot.setAngle(Math.PI / 180.0 * angle); gxyplot.setBackgroundPaint(new GradientPaint(0.0f, 0.0f, c0, 0.0f, 0.0f, c1)); } } else { throw new RuntimeException("'c' background fill not implemented yet."); } } else { throw new RuntimeException("Bad fill specification: " + spec); } } /** * Process a string which specifies grid line steps and line segment sizes. * * @param spec the grid lines specification. * @param chart the chart. */ private static void processGridLinesSpec(String spec, JFreeChart chart) { String[] parts = breakString(spec, ','); double xAxisStepSize = 0.0; double yAxisStepSize = 0.0; float lineSegLength = 3f; float blankSegLength = 6f; if (parts.length > 0) { try { xAxisStepSize = Double.parseDouble(parts[0]); } catch (NumberFormatException e) { } } if (parts.length > 1) { try { yAxisStepSize = Double.parseDouble(parts[1]); } catch (NumberFormatException e) { } } if (parts.length > 2) { try { lineSegLength = Float.parseFloat(parts[2]) * 0.85f; } catch (NumberFormatException e) { } } if (parts.length > 3) { try { blankSegLength = Float.parseFloat(parts[3]) * 0.85f; } catch (NumberFormatException e) { } } if (lineSegLength == 0 && blankSegLength == 0) { lineSegLength = 1f; } if (lineSegLength > 0) { Stroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10f, new float[] { lineSegLength, blankSegLength }, 0); Plot p = chart.getPlot(); if (p instanceof CategoryPlot) { GCategoryPlot plot = (GCategoryPlot) p; plot.setDomainGridlinesVisible(true); plot.setRangeGridlinesVisible(true); plot.setDomainGridlineStroke(stroke); plot.setRangeGridlineStroke(stroke); plot.setXAxisStepSize(xAxisStepSize / 100.0); plot.setYAxisStepSize(yAxisStepSize / 100.0); } else if (p instanceof XYPlot) { GXYPlot plot = (GXYPlot) p; plot.setDomainGridlinesVisible(true); plot.setRangeGridlinesVisible(true); plot.setDomainGridlineStroke(stroke); plot.setRangeGridlineStroke(stroke); plot.setXAxisStepSize(xAxisStepSize / 100.0); plot.setYAxisStepSize(yAxisStepSize / 100.0); } } } /** * Parses a string containing the chart dimensions. * * @param text the text (<code>null</code> not permitted). * * @return The chart dimensions. */ public static Dimension parseDimensions(String text) { if (text == null) { throw new IllegalArgumentException("Null 'text' argument (in parseChartDimensions(String))."); } int splitIndex = text.indexOf('x'); String xStr = text.substring(0, splitIndex); String yStr = text.substring(splitIndex + 1); int x = Integer.parseInt(xStr); int y = Integer.parseInt(yStr); return new Dimension(x, y); } }