/** * * The MIT License * * Copyright (c) 2011 the original author or authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.googlecode.charts4j; import static com.googlecode.charts4j.Color.BLACK; import static com.googlecode.charts4j.collect.Preconditions.checkArgument; import static com.googlecode.charts4j.collect.Preconditions.checkContentsNotNull; import java.util.List; import com.googlecode.charts4j.BarChartPlot.BarColor; import com.googlecode.charts4j.collect.ImmutableList; import com.googlecode.charts4j.collect.Lists; import com.googlecode.charts4j.parameters.ChartType; import com.googlecode.charts4j.parameters.FillAreaType; /** * Bar chart constructed with the {@link GCharts} static factory class. * * Bar chart class that supports vertical and horizontal bar charts. Bars from * different data series can either be stacked or side-by-side. * * @author Julien Chastang (julien.c.chastang at gmail dot com) * * @see BarChartPlot * @see GCharts */ public class BarChart extends AbstractAxisChart { /** Automatically resize bars to fit space. **/ public static final int AUTO_RESIZE = 0; /** Default space within groups of bars. **/ private static final int DEFAULT_SPACE_WINTHIN_GROUPS_OF_BARS = 4; /** Default space between groups of bars. **/ private static final int DEFAULT_SPACE_BETWEEN_GROUPS_OF_BARS = 8; /** Default bar width. **/ private static final int DEFAULT_BAR_WIDTH = 23; /** Are the bars stacked or side-by-side. **/ private boolean dataStacked = false; /** Are the bars horizontal or vertical. **/ private boolean horizontal = false; /** The bar width. **/ private int barWidth = DEFAULT_BAR_WIDTH; /** Space between groups of bars. **/ private int spaceBetweenGroupsOfBars = DEFAULT_SPACE_BETWEEN_GROUPS_OF_BARS; /** Space within groups. **/ private int spaceWithinGroupsOfBars = DEFAULT_SPACE_WINTHIN_GROUPS_OF_BARS; /** List of bars to be plotted. **/ private final ImmutableList<Plot> barChartPlots; /** * @see GCharts#newBarChart(List) */ BarChart(final ImmutableList<? extends Plot> barChartPlots) { super(); checkContentsNotNull(barChartPlots, "barChartPlots is null or contains a null plot"); this.barChartPlots = Lists.copyOf(barChartPlots); } /** * Are the bar charts stacked, or side-by-side. * * @param dataStacked * If true, data from different bar chart plot will be stacked * instead of side-by-side. */ public final void setDataStacked(final boolean dataStacked) { this.dataStacked = dataStacked; } /** * Is the bar chart bars horizontal or vertical. * * @param horizontal * If true, the bar chart will be horizontal instead of vertical. */ public final void setHorizontal(final boolean horizontal) { this.horizontal = horizontal; } /** * {@inheritDoc} */ @Override protected void prepareData() { super.prepareData(); // Logic to make sure things stay in step. boolean hasLegend = false; boolean hasColor = false; boolean hasZeroLine = false; // Logic to make sure things stay in step continued. for (Plot plot : barChartPlots) { final PlotImpl series = (PlotImpl) plot; hasLegend |= (series.getLegend() != null); hasColor |= (series.getColor() != null || !series.getBarColors().isEmpty()); hasZeroLine |= (series.getZeroLine() != 0); } // Logic to make sure things stay in step continued. int lineCount = 0; for (Plot p : barChartPlots) { final PlotImpl plot = (PlotImpl) p; parameterManager.addData(plot.getData()); if (hasLegend) { parameterManager.addLegend(plot.getLegend() != null ? plot.getLegend() : " "); } //Color logic is complicated b/c individual bars can be colored. if (hasColor) { if (plot.getBarColors().isEmpty()) { parameterManager.addColor(plot.getColor() != null ? plot.getColor() : BLACK); } else { final List<ImmutableList<Color>> colors = Lists.newArrayList(); final List<Color> colorList = Lists.newLinkedList(); //Initialize color list. for (int i = 0; i < plot.getData().getSize(); i++) { colorList.add(plot.getColor() != null ? plot.getColor() : BLACK); } //Now set the color on inidvidual bars. for (BarColor bColor : plot.getBarColors()) { if (bColor.getIndex() < plot.getData().getSize()) { colorList.set(bColor.getIndex(), bColor.getColor()); } } colors.add(Lists.copyOf(colorList)); parameterManager.addColors(Lists.copyOf(colors)); } } if (hasZeroLine) { // Remember zero line has to be between 0 and 1 parameterManager.setBarChartZeroLineParameter(plot.getZeroLine() / Data.MAX_VALUE); } if (plot.getDataLine() != null) { parameterManager.addLineStyleMarker(plot.getDataLine().getColor(), lineCount, 0, plot.getDataLine().getSize(), plot.getDataLine().getPriority()); } for (Marker m : plot.getMarkers()) { parameterManager.addMarkers(m, lineCount); } for (MarkedPoints mp : plot.getMarkedPointsList()) { parameterManager.addMarker(mp.getMarker(), lineCount, mp.getStartIndex(), mp.getEndIndex(), mp.getN()); } if (plot.getFillAreaColor() != null) { parameterManager.addFillAreaMarker(FillAreaType.FULL, plot.getFillAreaColor(), lineCount, 0); } lineCount++; } parameterManager.setBarChartWidthAndSpacingParameter(barWidth, spaceWithinGroupsOfBars, spaceBetweenGroupsOfBars); if (horizontal && dataStacked) { parameterManager.setChartTypeParameter(ChartType.HORIZONTAL_STACKED_BAR_CHART); } if (!horizontal && dataStacked) { parameterManager.setChartTypeParameter(ChartType.VERTICAL_STACKED_BAR_CHART); } if (!horizontal && !dataStacked) { parameterManager.setChartTypeParameter(ChartType.VERTICAL_GROUPED_BAR_CHART); } if (horizontal && !dataStacked) { parameterManager.setChartTypeParameter(ChartType.HORIZONTAL_GROUPED_BAR_CHART); } } /** * Set the bar chart width. * * @param barWidth * Bar width in pixels. If not set defaults to 23. Must be > 0. * To automatically resize bars to fit space use AUTO_RESIZE. * Example <code>chart.setBarWidth(BarChart.AUTO_RESIZE);</code> */ public final void setBarWidth(final int barWidth) { checkArgument(barWidth > -1, "barWidth must be > 0"); this.barWidth = barWidth; } /** * Set the space between groups of bars. * * @param spaceBetweenGroupsOfBars * The space between groups of bars. Bars within a group have * half the specified spacing. If not set default to 8. Must be >= * 0. */ public final void setSpaceBetweenGroupsOfBars(final int spaceBetweenGroupsOfBars) { checkArgument(spaceWithinGroupsOfBars >= 0, "spaceWithinGroupsOfBars must be >= 0"); this.spaceBetweenGroupsOfBars = spaceBetweenGroupsOfBars; } /** * Set the space within groups of bars. * * @param spaceWithinGroupsOfBars * The space within groups of bars. Bars within a group have half * the specified spacing. If not set default to 4. Must be >= 0. */ public final void setSpaceWithinGroupsOfBars(final int spaceWithinGroupsOfBars) { checkArgument(spaceWithinGroupsOfBars >= 0, "spaceWithinGroupsOfBars must be >= 0"); this.spaceWithinGroupsOfBars = spaceWithinGroupsOfBars; } }