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.CategorySeries;
\r
19 import org.achartengine.renderer.DefaultRenderer;
\r
20 import org.achartengine.renderer.DialRenderer;
\r
21 import org.achartengine.renderer.DialRenderer.Type;
\r
22 import org.achartengine.util.MathHelper;
\r
24 import android.graphics.Canvas;
\r
25 import android.graphics.Paint;
\r
26 import android.graphics.Paint.Align;
\r
27 import android.graphics.Paint.Style;
\r
30 * The dial chart rendering class.
\r
32 public class DialChart extends RoundChart {
\r
33 /** The radius of the needle. */
\r
34 private static final int NEEDLE_RADIUS = 10;
\r
35 /** The series renderer. */
\r
36 private DialRenderer mRenderer;
\r
39 * Builds a new dial chart instance.
\r
41 * @param dataset the series dataset
\r
42 * @param renderer the dial renderer
\r
44 public DialChart(CategorySeries dataset, DialRenderer renderer) {
\r
45 super(dataset, renderer);
\r
46 mRenderer = renderer;
\r
50 * The graphical representation of the dial chart.
\r
52 * @param canvas the canvas to paint to
\r
53 * @param x the top left x value of the view to draw to
\r
54 * @param y the top left y value of the view to draw to
\r
55 * @param width the width of the view to draw to
\r
56 * @param height the height of the view to draw to
\r
57 * @param paint the paint
\r
60 public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
\r
61 paint.setAntiAlias(mRenderer.isAntialiasing());
\r
62 paint.setStyle(Style.FILL);
\r
63 paint.setTextSize(mRenderer.getLabelsTextSize());
\r
64 int legendSize = getLegendSize(mRenderer, height / 5, 0);
\r
67 int right = x + width;
\r
69 int sLength = mDataset.getItemCount();
\r
70 String[] titles = new String[sLength];
\r
71 for (int i = 0; i < sLength; i++) {
\r
72 titles[i] = mDataset.getCategory(i);
\r
75 if (mRenderer.isFitLegend()) {
\r
76 legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,
\r
79 int bottom = y + height - legendSize;
\r
80 drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
\r
82 int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
\r
83 int radius = (int) (mRadius * 0.35 * mRenderer.getScale());
\r
84 if (mCenterX == NO_VALUE) {
\r
85 mCenterX = (left + right) / 2;
\r
87 if (mCenterY == NO_VALUE) {
\r
88 mCenterY = (bottom + top) / 2;
\r
90 float shortRadius = radius * 0.9f;
\r
91 float longRadius = radius * 1.1f;
\r
92 double min = mRenderer.getMinValue();
\r
93 double max = mRenderer.getMaxValue();
\r
94 double angleMin = mRenderer.getAngleMin();
\r
95 double angleMax = mRenderer.getAngleMax();
\r
96 if (!mRenderer.isMinValueSet() || !mRenderer.isMaxValueSet()) {
\r
97 int count = mRenderer.getSeriesRendererCount();
\r
98 for (int i = 0; i < count; i++) {
\r
99 double value = mDataset.getValue(i);
\r
100 if (!mRenderer.isMinValueSet()) {
\r
101 min = Math.min(min, value);
\r
103 if (!mRenderer.isMaxValueSet()) {
\r
104 max = Math.max(max, value);
\r
113 paint.setColor(mRenderer.getLabelsColor());
\r
114 double minorTicks = mRenderer.getMinorTicksSpacing();
\r
115 double majorTicks = mRenderer.getMajorTicksSpacing();
\r
116 if (minorTicks == MathHelper.NULL_VALUE) {
\r
117 minorTicks = (max - min) / 30;
\r
119 if (majorTicks == MathHelper.NULL_VALUE) {
\r
120 majorTicks = (max - min) / 10;
\r
122 drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, radius,
\r
123 minorTicks, paint, false);
\r
124 drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, shortRadius,
\r
125 majorTicks, paint, true);
\r
127 int count = mRenderer.getSeriesRendererCount();
\r
128 for (int i = 0; i < count; i++) {
\r
129 double angle = getAngleForValue(mDataset.getValue(i), angleMin, angleMax, min, max);
\r
130 paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());
\r
131 boolean type = mRenderer.getVisualTypeForIndex(i) == Type.ARROW;
\r
132 drawNeedle(canvas, angle, mCenterX, mCenterY, shortRadius, type, paint);
\r
134 drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
\r
135 drawTitle(canvas, x, y, width, paint);
\r
139 * Returns the angle for a specific chart value.
\r
141 * @param value the chart value
\r
142 * @param minAngle the minimum chart angle value
\r
143 * @param maxAngle the maximum chart angle value
\r
144 * @param min the minimum chart value
\r
145 * @param max the maximum chart value
\r
146 * @return the angle
\r
148 private double getAngleForValue(double value, double minAngle, double maxAngle, double min,
\r
150 double angleDiff = maxAngle - minAngle;
\r
151 double diff = max - min;
\r
152 return Math.toRadians(minAngle + (value - min) * angleDiff / diff);
\r
156 * Draws the chart tick lines.
\r
158 * @param canvas the canvas
\r
159 * @param min the minimum chart value
\r
160 * @param max the maximum chart value
\r
161 * @param minAngle the minimum chart angle value
\r
162 * @param maxAngle the maximum chart angle value
\r
163 * @param centerX the center x value
\r
164 * @param centerY the center y value
\r
165 * @param longRadius the long radius
\r
166 * @param shortRadius the short radius
\r
167 * @param ticks the tick spacing
\r
168 * @param paint the paint settings
\r
169 * @param labels paint the labels
\r
170 * @return the angle
\r
172 private void drawTicks(Canvas canvas, double min, double max, double minAngle, double maxAngle,
\r
173 int centerX, int centerY, double longRadius, double shortRadius, double ticks, Paint paint,
\r
175 for (double i = min; i <= max; i += ticks) {
\r
176 double angle = getAngleForValue(i, minAngle, maxAngle, min, max);
\r
177 double sinValue = Math.sin(angle);
\r
178 double cosValue = Math.cos(angle);
\r
179 int x1 = Math.round(centerX + (float) (shortRadius * sinValue));
\r
180 int y1 = Math.round(centerY + (float) (shortRadius * cosValue));
\r
181 int x2 = Math.round(centerX + (float) (longRadius * sinValue));
\r
182 int y2 = Math.round(centerY + (float) (longRadius * cosValue));
\r
183 canvas.drawLine(x1, y1, x2, y2, paint);
\r
185 paint.setTextAlign(Align.LEFT);
\r
187 paint.setTextAlign(Align.RIGHT);
\r
189 String text = i + "";
\r
190 if (Math.round(i) == (long) i) {
\r
191 text = (long) i + "";
\r
193 canvas.drawText(text, x1, y1, paint);
\r
199 * Returns the angle for a specific chart value.
\r
201 * @param canvas the canvas
\r
202 * @param angle the needle angle value
\r
203 * @param centerX the center x value
\r
204 * @param centerY the center y value
\r
205 * @param radius the radius
\r
206 * @param arrow if a needle or an arrow to be painted
\r
207 * @param paint the paint settings
\r
208 * @return the angle
\r
210 private void drawNeedle(Canvas canvas, double angle, int centerX, int centerY, double radius,
\r
211 boolean arrow, Paint paint) {
\r
212 double diff = Math.toRadians(90);
\r
213 int needleSinValue = (int) (NEEDLE_RADIUS * Math.sin(angle - diff));
\r
214 int needleCosValue = (int) (NEEDLE_RADIUS * Math.cos(angle - diff));
\r
215 int needleX = (int) (radius * Math.sin(angle));
\r
216 int needleY = (int) (radius * Math.cos(angle));
\r
217 int needleCenterX = centerX + needleX;
\r
218 int needleCenterY = centerY + needleY;
\r
221 int arrowBaseX = centerX + (int) (radius * 0.85 * Math.sin(angle));
\r
222 int arrowBaseY = centerY + (int) (radius * 0.85 * Math.cos(angle));
\r
223 points = new float[] { arrowBaseX - needleSinValue, arrowBaseY - needleCosValue,
\r
224 needleCenterX, needleCenterY, arrowBaseX + needleSinValue, arrowBaseY + needleCosValue };
\r
225 float width = paint.getStrokeWidth();
\r
226 paint.setStrokeWidth(5);
\r
227 canvas.drawLine(centerX, centerY, needleCenterX, needleCenterY, paint);
\r
228 paint.setStrokeWidth(width);
\r
230 points = new float[] { centerX - needleSinValue, centerY - needleCosValue, needleCenterX,
\r
231 needleCenterY, centerX + needleSinValue, centerY + needleCosValue };
\r
233 drawPath(canvas, points, paint, true);
\r