create changelog entry
[debian/openrocket] / android-libraries / achartengine / src / org / achartengine / chart / TimeChart.java
1 /**\r
2  * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
3  *  \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
7  *  \r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *  \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
15  */\r
16 package org.achartengine.chart;\r
17 \r
18 import java.text.DateFormat;\r
19 import java.text.SimpleDateFormat;\r
20 import java.util.ArrayList;\r
21 import java.util.Date;\r
22 import java.util.List;\r
23 \r
24 import org.achartengine.model.XYMultipleSeriesDataset;\r
25 import org.achartengine.model.XYSeries;\r
26 import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
27 \r
28 import android.graphics.Canvas;\r
29 import android.graphics.Paint;\r
30 \r
31 /**\r
32  * The time chart rendering class.\r
33  */\r
34 public class TimeChart extends LineChart {\r
35   /** The constant to identify this chart type. */\r
36   public static final String TYPE = "Time";\r
37   /** The number of milliseconds in a day. */\r
38   public static final long DAY = 24 * 60 * 60 * 1000;\r
39   /** The date format pattern to be used in formatting the X axis labels. */\r
40   private String mDateFormat;\r
41   /** The starting point for labels. */\r
42   private Double mStartPoint;\r
43 \r
44   TimeChart() {\r
45   }\r
46 \r
47   /**\r
48    * Builds a new time chart instance.\r
49    * \r
50    * @param dataset the multiple series dataset\r
51    * @param renderer the multiple series renderer\r
52    */\r
53   public TimeChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
54     super(dataset, renderer);\r
55   }\r
56 \r
57   /**\r
58    * Returns the date format pattern to be used for formatting the X axis\r
59    * labels.\r
60    * \r
61    * @return the date format pattern for the X axis labels\r
62    */\r
63   public String getDateFormat() {\r
64     return mDateFormat;\r
65   }\r
66 \r
67   /**\r
68    * Sets the date format pattern to be used for formatting the X axis labels.\r
69    * \r
70    * @param format the date format pattern for the X axis labels. If null, an\r
71    *          appropriate default format will be used.\r
72    */\r
73   public void setDateFormat(String format) {\r
74     mDateFormat = format;\r
75   }\r
76 \r
77   /**\r
78    * The graphical representation of the labels on the X axis.\r
79    * \r
80    * @param xLabels the X labels values\r
81    * @param xTextLabelLocations the X text label locations\r
82    * @param canvas the canvas to paint to\r
83    * @param paint the paint to be used for drawing\r
84    * @param left the left value of the labels area\r
85    * @param top the top value of the labels area\r
86    * @param bottom the bottom value of the labels area\r
87    * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
88    * @param minX the minimum value on the X axis in the chart\r
89    * @param maxX the maximum value on the X axis in the chart\r
90    */\r
91   @Override\r
92   protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,\r
93       Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {\r
94     int length = xLabels.size();\r
95     if (length > 0) {\r
96       boolean showLabels = mRenderer.isShowLabels();\r
97       boolean showGridY = mRenderer.isShowGridY();\r
98       DateFormat format = getDateFormat(xLabels.get(0), xLabels.get(length - 1));\r
99       for (int i = 0; i < length; i++) {\r
100         long label = Math.round(xLabels.get(i));\r
101         float xLabel = (float) (left + xPixelsPerUnit * (label - minX));\r
102         if (showLabels) {\r
103           paint.setColor(mRenderer.getXLabelsColor());\r
104           canvas\r
105               .drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
106           drawText(canvas, format.format(new Date(label)), xLabel,\r
107               bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());\r
108         }\r
109         if (showGridY) {\r
110           paint.setColor(mRenderer.getGridColor());\r
111           canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
112         }\r
113       }\r
114     }\r
115     drawXTextLabels(xTextLabelLocations, canvas, paint, true, left, top, bottom, xPixelsPerUnit,\r
116         minX, maxX);\r
117   }\r
118 \r
119   /**\r
120    * Returns the date format pattern to be used, based on the date range.\r
121    * \r
122    * @param start the start date in milliseconds\r
123    * @param end the end date in milliseconds\r
124    * @return the date format\r
125    */\r
126   private DateFormat getDateFormat(double start, double end) {\r
127     if (mDateFormat != null) {\r
128       SimpleDateFormat format = null;\r
129       try {\r
130         format = new SimpleDateFormat(mDateFormat);\r
131         return format;\r
132       } catch (Exception e) {\r
133         // do nothing here\r
134       }\r
135     }\r
136     DateFormat format = SimpleDateFormat.getDateInstance(SimpleDateFormat.MEDIUM);\r
137     double diff = end - start;\r
138     if (diff > DAY && diff < 5 * DAY) {\r
139       format = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);\r
140     } else if (diff < DAY) {\r
141       format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM);\r
142     }\r
143     return format;\r
144   }\r
145 \r
146   /**\r
147    * Returns the chart type identifier.\r
148    * \r
149    * @return the chart type\r
150    */\r
151   public String getChartType() {\r
152     return TYPE;\r
153   }\r
154 \r
155   protected List<Double> getXLabels(double min, double max, int count) {\r
156     final List<Double> result = new ArrayList<Double>();\r
157     if (!mRenderer.isXRoundedLabels()) {\r
158       if (mDataset.getSeriesCount() > 0) {\r
159         XYSeries series = mDataset.getSeriesAt(0);\r
160         int length = series.getItemCount();\r
161         int intervalLength = 0;\r
162         int startIndex = -1;\r
163         for (int i = 0; i < length; i++) {\r
164           double value = series.getX(i);\r
165           if (min <= value && value <= max) {\r
166             intervalLength++;\r
167             if (startIndex < 0) {\r
168               startIndex = i;\r
169             }\r
170           }\r
171         }\r
172         if (intervalLength < count) {\r
173           for (int i = startIndex; i < startIndex + intervalLength; i++) {\r
174             result.add(series.getX(i));\r
175           }\r
176         } else {\r
177           float step = (float) intervalLength / count;\r
178           int intervalCount = 0;\r
179           for (int i = 0; i < length && intervalCount < count; i++) {\r
180             double value = series.getX(Math.round(i * step));\r
181             if (min <= value && value <= max) {\r
182               result.add(value);\r
183               intervalCount++;\r
184             }\r
185           }\r
186         }\r
187         return result;\r
188       } else {\r
189         return super.getXLabels(min, max, count);\r
190       }\r
191     }\r
192     if (mStartPoint == null) {\r
193       mStartPoint = min - (min % DAY) + DAY + new Date(Math.round(min)).getTimezoneOffset() * 60\r
194           * 1000;\r
195     }\r
196     if (count > 25) {\r
197       count = 25;\r
198     }\r
199 \r
200     \r
201     final double cycleMath = (max - min) / count;\r
202     if (cycleMath <= 0) {\r
203       return result;\r
204     }\r
205     double cycle = DAY;\r
206 \r
207     if (cycleMath <= DAY) {\r
208       while (cycleMath < cycle / 2) {\r
209         cycle = cycle / 2;\r
210       }\r
211     } else {\r
212       while (cycleMath > cycle) {\r
213         cycle = cycle * 2;\r
214       }\r
215     }\r
216 \r
217     double val = mStartPoint - Math.floor((mStartPoint - min) / cycle) * cycle;\r
218     int i = 0;\r
219     while (val < max && i++ <= count) {\r
220       result.add(val);\r
221       val += cycle;\r
222     }\r
223 \r
224     return result;\r
225   }\r
226 }\r