--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+import android.graphics.drawable.GradientDrawable;\r
+import android.graphics.drawable.GradientDrawable.Orientation;\r
+\r
+/**\r
+ * The bar chart rendering class.\r
+ */\r
+public class BarChart extends XYChart {\r
+ /** The constant to identify this chart type. */\r
+ public static final String TYPE = "Bar";\r
+ /** The legend shape width. */\r
+ private static final int SHAPE_WIDTH = 12;\r
+ /** The chart type. */\r
+ protected Type mType = Type.DEFAULT;\r
+\r
+ /**\r
+ * The bar chart type enum.\r
+ */\r
+ public enum Type {\r
+ DEFAULT, STACKED;\r
+ }\r
+\r
+ BarChart() {\r
+ }\r
+\r
+ BarChart(Type type) {\r
+ mType = type;\r
+ }\r
+\r
+ /**\r
+ * Builds a new bar chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ * @param type the bar chart type\r
+ */\r
+ public BarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+ super(dataset, renderer);\r
+ mType = type;\r
+ }\r
+\r
+ @Override\r
+ protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ int length = points.length;\r
+ ClickableArea[] ret = new ClickableArea[length / 2];\r
+ float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+ for (int i = 0; i < length; i += 2) {\r
+ float x = points[i];\r
+ float y = points[i + 1];\r
+ if (mType == Type.STACKED) {\r
+ ret[i / 2] = new ClickableArea(new RectF(x - halfDiffX, y, x + halfDiffX, yAxisValue),\r
+ values[i], values[i + 1]);\r
+ } else {\r
+ float startX = x - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;\r
+ ret[i / 2] = new ClickableArea(new RectF(startX, y, startX + 2 * halfDiffX, yAxisValue),\r
+ values[i], values[i + 1]);\r
+ }\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ int length = points.length;\r
+ paint.setColor(seriesRenderer.getColor());\r
+ paint.setStyle(Style.FILL);\r
+ float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+ for (int i = 0; i < length; i += 2) {\r
+ float x = points[i];\r
+ float y = points[i + 1];\r
+ drawBar(canvas, x, yAxisValue, x, y, halfDiffX, seriesNr, seriesIndex, paint);\r
+ }\r
+ paint.setColor(seriesRenderer.getColor());\r
+ }\r
+\r
+ /**\r
+ * Draws a bar.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param xMin the X axis minimum\r
+ * @param yMin the Y axis minimum\r
+ * @param xMax the X axis maximum\r
+ * @param yMax the Y axis maximum\r
+ * @param halfDiffX half the size of a bar\r
+ * @param seriesNr the total number of series\r
+ * @param seriesIndex the current series index\r
+ * @param paint the paint\r
+ */\r
+ protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax,\r
+ float halfDiffX, int seriesNr, int seriesIndex, Paint paint) {\r
+ int scale = mDataset.getSeriesAt(seriesIndex).getScaleNumber();\r
+ if (mType == Type.STACKED) {\r
+ drawBar(canvas, xMin - halfDiffX, yMax, xMax + halfDiffX, yMin, scale, seriesIndex, paint);\r
+ } else {\r
+ float startX = xMin - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;\r
+ drawBar(canvas, startX, yMax, startX + 2 * halfDiffX, yMin, scale, seriesIndex, paint);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Draws a bar.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param xMin the X axis minimum\r
+ * @param yMin the Y axis minimum\r
+ * @param xMax the X axis maximum\r
+ * @param yMax the Y axis maximum\r
+ * @param scale the scale index\r
+ * @param seriesIndex the current series index\r
+ * @param paint the paint\r
+ */\r
+ private void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax, int scale,\r
+ int seriesIndex, Paint paint) {\r
+ SimpleSeriesRenderer renderer = mRenderer.getSeriesRendererAt(seriesIndex);\r
+ if (renderer.isGradientEnabled()) {\r
+ float minY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStopValue() }, scale)[1];\r
+ float maxY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStartValue() },\r
+ scale)[1];\r
+ float gradientMinY = Math.max(minY, Math.min(yMin, yMax));\r
+ float gradientMaxY = Math.min(maxY, Math.max(yMin, yMax));\r
+ int gradientMinColor = renderer.getGradientStopColor();\r
+ int gradientMaxColor = renderer.getGradientStartColor();\r
+ int gradientStartColor = gradientMaxColor;\r
+ int gradientStopColor = gradientMinColor;\r
+\r
+ if (yMin < minY) {\r
+ paint.setColor(gradientMinColor);\r
+ canvas.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax),\r
+ Math.round(gradientMinY), paint);\r
+ } else {\r
+ gradientStopColor = getGradientPartialColor(gradientMinColor, gradientMaxColor,\r
+ (maxY - gradientMinY) / (maxY - minY));\r
+ }\r
+ if (yMax > maxY) {\r
+ paint.setColor(gradientMaxColor);\r
+ canvas.drawRect(Math.round(xMin), Math.round(gradientMaxY), Math.round(xMax),\r
+ Math.round(yMax), paint);\r
+ } else {\r
+ gradientStartColor = getGradientPartialColor(gradientMaxColor, gradientMinColor,\r
+ (gradientMaxY - minY) / (maxY - minY));\r
+ }\r
+ GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {\r
+ gradientStartColor, gradientStopColor });\r
+ gradient.setBounds(Math.round(xMin), Math.round(gradientMinY), Math.round(xMax),\r
+ Math.round(gradientMaxY));\r
+ gradient.draw(canvas);\r
+ } else {\r
+ if (Math.abs(yMin - yMax) < 1) {\r
+ if (yMin < yMax) {\r
+ yMax = yMin + 1;\r
+ } else {\r
+ yMax = yMin - 1;\r
+ }\r
+ }\r
+ canvas\r
+ .drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax), Math.round(yMax), paint);\r
+ }\r
+ }\r
+\r
+ private int getGradientPartialColor(int minColor, int maxColor, float fraction) {\r
+ int alpha = Math.round(fraction * Color.alpha(minColor) + (1 - fraction)\r
+ * Color.alpha(maxColor));\r
+ int r = Math.round(fraction * Color.red(minColor) + (1 - fraction) * Color.red(maxColor));\r
+ int g = Math.round(fraction * Color.green(minColor) + (1 - fraction) * Color.green(maxColor));\r
+ int b = Math.round(fraction * Color.blue(minColor) + (1 - fraction) * Color.blue((maxColor)));\r
+ return Color.argb(alpha, r, g, b);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the series values as text.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param series the series to be painted\r
+ * @param renderer the series renderer\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+ Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ float halfDiffX = getHalfDiffX(points, points.length, seriesNr);\r
+ for (int i = 0; i < points.length; i += 2) {\r
+ int index = startIndex + i / 2;\r
+ double value = series.getY(index);\r
+ if (!isNullValue(value)) {\r
+ float x = points[i];\r
+ if (mType == Type.DEFAULT) {\r
+ x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;\r
+ }\r
+ if (value >= 0) {\r
+ drawText(canvas, getLabel(value), x, points[i + 1] - renderer.getChartValuesSpacing(),\r
+ paint, 0);\r
+ } else {\r
+ drawText(canvas, getLabel(value), x, points[i + 1] + renderer.getChartValuesTextSize()\r
+ + renderer.getChartValuesSpacing() - 3, paint, 0);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ float halfShapeWidth = SHAPE_WIDTH / 2;\r
+ canvas.drawRect(x, y - halfShapeWidth, x + SHAPE_WIDTH, y + halfShapeWidth, paint);\r
+ }\r
+\r
+ /**\r
+ * Calculates and returns the half-distance in the graphical representation of\r
+ * 2 consecutive points.\r
+ * \r
+ * @param points the points\r
+ * @param length the points length\r
+ * @param seriesNr the series number\r
+ * @return the calculated half-distance value\r
+ */\r
+ protected float getHalfDiffX(float[] points, int length, int seriesNr) {\r
+ int div = length;\r
+ if (length > 2) {\r
+ div = length - 2;\r
+ }\r
+ float halfDiffX = (points[length - 2] - points[0]) / div;\r
+ if (halfDiffX == 0) {\r
+ halfDiffX = 10;\r
+ }\r
+\r
+ if (mType != Type.STACKED) {\r
+ halfDiffX /= seriesNr;\r
+ }\r
+ return (float) (halfDiffX / (getCoeficient() * (1 + mRenderer.getBarSpacing())));\r
+ }\r
+\r
+ /**\r
+ * Returns the value of a constant used to calculate the half-distance.\r
+ * \r
+ * @return the constant value\r
+ */\r
+ protected float getCoeficient() {\r
+ return 1f;\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart should display the null values.\r
+ * \r
+ * @return if null values should be rendered\r
+ */\r
+ protected boolean isRenderNullValues() {\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Returns the default axis minimum.\r
+ * \r
+ * @return the default axis minimum\r
+ */\r
+ public double getDefaultMinimum() {\r
+ return 0;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+}\r