2 * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
16 package org.achartengine.chart;
\r
18 import org.achartengine.model.XYMultipleSeriesDataset;
\r
19 import org.achartengine.model.XYSeries;
\r
20 import org.achartengine.renderer.SimpleSeriesRenderer;
\r
21 import org.achartengine.renderer.XYMultipleSeriesRenderer;
\r
23 import android.graphics.Canvas;
\r
24 import android.graphics.Color;
\r
25 import android.graphics.Paint;
\r
26 import android.graphics.Paint.Style;
\r
27 import android.graphics.RectF;
\r
28 import android.graphics.drawable.GradientDrawable;
\r
29 import android.graphics.drawable.GradientDrawable.Orientation;
\r
32 * The bar chart rendering class.
\r
34 public class BarChart extends XYChart {
\r
35 /** The constant to identify this chart type. */
\r
36 public static final String TYPE = "Bar";
\r
37 /** The legend shape width. */
\r
38 private static final int SHAPE_WIDTH = 12;
\r
39 /** The chart type. */
\r
40 protected Type mType = Type.DEFAULT;
\r
43 * The bar chart type enum.
\r
52 BarChart(Type type) {
\r
57 * Builds a new bar chart instance.
\r
59 * @param dataset the multiple series dataset
\r
60 * @param renderer the multiple series renderer
\r
61 * @param type the bar chart type
\r
63 public BarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
\r
64 super(dataset, renderer);
\r
69 protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,
\r
70 float yAxisValue, int seriesIndex, int startIndex) {
\r
71 int seriesNr = mDataset.getSeriesCount();
\r
72 int length = points.length;
\r
73 ClickableArea[] ret = new ClickableArea[length / 2];
\r
74 float halfDiffX = getHalfDiffX(points, length, seriesNr);
\r
75 for (int i = 0; i < length; i += 2) {
\r
76 float x = points[i];
\r
77 float y = points[i + 1];
\r
78 if (mType == Type.STACKED) {
\r
79 ret[i / 2] = new ClickableArea(new RectF(x - halfDiffX, y, x + halfDiffX, yAxisValue),
\r
80 values[i], values[i + 1]);
\r
82 float startX = x - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;
\r
83 ret[i / 2] = new ClickableArea(new RectF(startX, y, startX + 2 * halfDiffX, yAxisValue),
\r
84 values[i], values[i + 1]);
\r
91 * The graphical representation of a series.
\r
93 * @param canvas the canvas to paint to
\r
94 * @param paint the paint to be used for drawing
\r
95 * @param points the array of points to be used for drawing the series
\r
96 * @param seriesRenderer the series renderer
\r
97 * @param yAxisValue the minimum value of the y axis
\r
98 * @param seriesIndex the index of the series currently being drawn
\r
99 * @param startIndex the start index of the rendering points
\r
101 public void drawSeries(Canvas canvas, Paint paint, float[] points,
\r
102 SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {
\r
103 int seriesNr = mDataset.getSeriesCount();
\r
104 int length = points.length;
\r
105 paint.setColor(seriesRenderer.getColor());
\r
106 paint.setStyle(Style.FILL);
\r
107 float halfDiffX = getHalfDiffX(points, length, seriesNr);
\r
108 for (int i = 0; i < length; i += 2) {
\r
109 float x = points[i];
\r
110 float y = points[i + 1];
\r
111 drawBar(canvas, x, yAxisValue, x, y, halfDiffX, seriesNr, seriesIndex, paint);
\r
113 paint.setColor(seriesRenderer.getColor());
\r
119 * @param canvas the canvas
\r
120 * @param xMin the X axis minimum
\r
121 * @param yMin the Y axis minimum
\r
122 * @param xMax the X axis maximum
\r
123 * @param yMax the Y axis maximum
\r
124 * @param halfDiffX half the size of a bar
\r
125 * @param seriesNr the total number of series
\r
126 * @param seriesIndex the current series index
\r
127 * @param paint the paint
\r
129 protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax,
\r
130 float halfDiffX, int seriesNr, int seriesIndex, Paint paint) {
\r
131 int scale = mDataset.getSeriesAt(seriesIndex).getScaleNumber();
\r
132 if (mType == Type.STACKED) {
\r
133 drawBar(canvas, xMin - halfDiffX, yMax, xMax + halfDiffX, yMin, scale, seriesIndex, paint);
\r
135 float startX = xMin - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;
\r
136 drawBar(canvas, startX, yMax, startX + 2 * halfDiffX, yMin, scale, seriesIndex, paint);
\r
143 * @param canvas the canvas
\r
144 * @param xMin the X axis minimum
\r
145 * @param yMin the Y axis minimum
\r
146 * @param xMax the X axis maximum
\r
147 * @param yMax the Y axis maximum
\r
148 * @param scale the scale index
\r
149 * @param seriesIndex the current series index
\r
150 * @param paint the paint
\r
152 private void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax, int scale,
\r
153 int seriesIndex, Paint paint) {
\r
154 SimpleSeriesRenderer renderer = mRenderer.getSeriesRendererAt(seriesIndex);
\r
155 if (renderer.isGradientEnabled()) {
\r
156 float minY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStopValue() }, scale)[1];
\r
157 float maxY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStartValue() },
\r
159 float gradientMinY = Math.max(minY, Math.min(yMin, yMax));
\r
160 float gradientMaxY = Math.min(maxY, Math.max(yMin, yMax));
\r
161 int gradientMinColor = renderer.getGradientStopColor();
\r
162 int gradientMaxColor = renderer.getGradientStartColor();
\r
163 int gradientStartColor = gradientMaxColor;
\r
164 int gradientStopColor = gradientMinColor;
\r
167 paint.setColor(gradientMinColor);
\r
168 canvas.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax),
\r
169 Math.round(gradientMinY), paint);
\r
171 gradientStopColor = getGradientPartialColor(gradientMinColor, gradientMaxColor,
\r
172 (maxY - gradientMinY) / (maxY - minY));
\r
175 paint.setColor(gradientMaxColor);
\r
176 canvas.drawRect(Math.round(xMin), Math.round(gradientMaxY), Math.round(xMax),
\r
177 Math.round(yMax), paint);
\r
179 gradientStartColor = getGradientPartialColor(gradientMaxColor, gradientMinColor,
\r
180 (gradientMaxY - minY) / (maxY - minY));
\r
182 GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {
\r
183 gradientStartColor, gradientStopColor });
\r
184 gradient.setBounds(Math.round(xMin), Math.round(gradientMinY), Math.round(xMax),
\r
185 Math.round(gradientMaxY));
\r
186 gradient.draw(canvas);
\r
188 if (Math.abs(yMin - yMax) < 1) {
\r
196 .drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax), Math.round(yMax), paint);
\r
200 private int getGradientPartialColor(int minColor, int maxColor, float fraction) {
\r
201 int alpha = Math.round(fraction * Color.alpha(minColor) + (1 - fraction)
\r
202 * Color.alpha(maxColor));
\r
203 int r = Math.round(fraction * Color.red(minColor) + (1 - fraction) * Color.red(maxColor));
\r
204 int g = Math.round(fraction * Color.green(minColor) + (1 - fraction) * Color.green(maxColor));
\r
205 int b = Math.round(fraction * Color.blue(minColor) + (1 - fraction) * Color.blue((maxColor)));
\r
206 return Color.argb(alpha, r, g, b);
\r
210 * The graphical representation of the series values as text.
\r
212 * @param canvas the canvas to paint to
\r
213 * @param series the series to be painted
\r
214 * @param renderer the series renderer
\r
215 * @param paint the paint to be used for drawing
\r
216 * @param points the array of points to be used for drawing the series
\r
217 * @param seriesIndex the index of the series currently being drawn
\r
218 * @param startIndex the start index of the rendering points
\r
220 protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,
\r
221 Paint paint, float[] points, int seriesIndex, int startIndex) {
\r
222 int seriesNr = mDataset.getSeriesCount();
\r
223 float halfDiffX = getHalfDiffX(points, points.length, seriesNr);
\r
224 for (int i = 0; i < points.length; i += 2) {
\r
225 int index = startIndex + i / 2;
\r
226 double value = series.getY(index);
\r
227 if (!isNullValue(value)) {
\r
228 float x = points[i];
\r
229 if (mType == Type.DEFAULT) {
\r
230 x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;
\r
233 drawText(canvas, getLabel(value), x, points[i + 1] - renderer.getChartValuesSpacing(),
\r
236 drawText(canvas, getLabel(value), x, points[i + 1] + renderer.getChartValuesTextSize()
\r
237 + renderer.getChartValuesSpacing() - 3, paint, 0);
\r
244 * Returns the legend shape width.
\r
246 * @param seriesIndex the series index
\r
247 * @return the legend shape width
\r
249 public int getLegendShapeWidth(int seriesIndex) {
\r
250 return SHAPE_WIDTH;
\r
254 * The graphical representation of the legend shape.
\r
256 * @param canvas the canvas to paint to
\r
257 * @param renderer the series renderer
\r
258 * @param x the x value of the point the shape should be drawn at
\r
259 * @param y the y value of the point the shape should be drawn at
\r
260 * @param seriesIndex the series index
\r
261 * @param paint the paint to be used for drawing
\r
263 public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
\r
264 int seriesIndex, Paint paint) {
\r
265 float halfShapeWidth = SHAPE_WIDTH / 2;
\r
266 canvas.drawRect(x, y - halfShapeWidth, x + SHAPE_WIDTH, y + halfShapeWidth, paint);
\r
270 * Calculates and returns the half-distance in the graphical representation of
\r
271 * 2 consecutive points.
\r
273 * @param points the points
\r
274 * @param length the points length
\r
275 * @param seriesNr the series number
\r
276 * @return the calculated half-distance value
\r
278 protected float getHalfDiffX(float[] points, int length, int seriesNr) {
\r
283 float halfDiffX = (points[length - 2] - points[0]) / div;
\r
284 if (halfDiffX == 0) {
\r
288 if (mType != Type.STACKED) {
\r
289 halfDiffX /= seriesNr;
\r
291 return (float) (halfDiffX / (getCoeficient() * (1 + mRenderer.getBarSpacing())));
\r
295 * Returns the value of a constant used to calculate the half-distance.
\r
297 * @return the constant value
\r
299 protected float getCoeficient() {
\r
304 * Returns if the chart should display the null values.
\r
306 * @return if null values should be rendered
\r
308 protected boolean isRenderNullValues() {
\r
313 * Returns the default axis minimum.
\r
315 * @return the default axis minimum
\r
317 public double getDefaultMinimum() {
\r
322 * Returns the chart type identifier.
\r
324 * @return the chart type
\r
326 public String getChartType() {
\r