• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 package com.github.mikephil.charting.renderer;
3 
4 import android.graphics.Canvas;
5 import android.graphics.Color;
6 import android.graphics.Paint;
7 import android.graphics.Paint.Style;
8 
9 import com.github.mikephil.charting.components.AxisBase;
10 import com.github.mikephil.charting.utils.MPPointD;
11 import com.github.mikephil.charting.utils.Transformer;
12 import com.github.mikephil.charting.utils.Utils;
13 import com.github.mikephil.charting.utils.ViewPortHandler;
14 
15 /**
16  * Baseclass of all axis renderers.
17  *
18  * @author Philipp Jahoda
19  */
20 public abstract class AxisRenderer extends Renderer {
21 
22     /** base axis this axis renderer works with */
23     protected AxisBase mAxis;
24 
25     /** transformer to transform values to screen pixels and return */
26     protected Transformer mTrans;
27 
28     /**
29      * paint object for the grid lines
30      */
31     protected Paint mGridPaint;
32 
33     /**
34      * paint for the x-label values
35      */
36     protected Paint mAxisLabelPaint;
37 
38     /**
39      * paint for the line surrounding the chart
40      */
41     protected Paint mAxisLinePaint;
42 
43     /**
44      * paint used for the limit lines
45      */
46     protected Paint mLimitLinePaint;
47 
AxisRenderer(ViewPortHandler viewPortHandler, Transformer trans, AxisBase axis)48     public AxisRenderer(ViewPortHandler viewPortHandler, Transformer trans, AxisBase axis) {
49         super(viewPortHandler);
50 
51         this.mTrans = trans;
52         this.mAxis = axis;
53 
54         if(mViewPortHandler != null) {
55 
56             mAxisLabelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
57 
58             mGridPaint = new Paint();
59             mGridPaint.setColor(Color.GRAY);
60             mGridPaint.setStrokeWidth(1f);
61             mGridPaint.setStyle(Style.STROKE);
62             mGridPaint.setAlpha(90);
63 
64             mAxisLinePaint = new Paint();
65             mAxisLinePaint.setColor(Color.BLACK);
66             mAxisLinePaint.setStrokeWidth(1f);
67             mAxisLinePaint.setStyle(Style.STROKE);
68 
69             mLimitLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
70             mLimitLinePaint.setStyle(Paint.Style.STROKE);
71         }
72     }
73 
74     /**
75      * Returns the Paint object used for drawing the axis (labels).
76      *
77      * @return
78      */
getPaintAxisLabels()79     public Paint getPaintAxisLabels() {
80         return mAxisLabelPaint;
81     }
82 
83     /**
84      * Returns the Paint object that is used for drawing the grid-lines of the
85      * axis.
86      *
87      * @return
88      */
getPaintGrid()89     public Paint getPaintGrid() {
90         return mGridPaint;
91     }
92 
93     /**
94      * Returns the Paint object that is used for drawing the axis-line that goes
95      * alongside the axis.
96      *
97      * @return
98      */
getPaintAxisLine()99     public Paint getPaintAxisLine() {
100         return mAxisLinePaint;
101     }
102 
103     /**
104      * Returns the Transformer object used for transforming the axis values.
105      *
106      * @return
107      */
getTransformer()108     public Transformer getTransformer() {
109         return mTrans;
110     }
111 
112     /**
113      * Computes the axis values.
114      *
115      * @param min - the minimum value in the data object for this axis
116      * @param max - the maximum value in the data object for this axis
117      */
computeAxis(float min, float max, boolean inverted)118     public void computeAxis(float min, float max, boolean inverted) {
119 
120         // calculate the starting and entry point of the y-labels (depending on
121         // zoom / contentrect bounds)
122         if (mViewPortHandler != null && mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutY()) {
123 
124             MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop());
125             MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom());
126 
127             if (!inverted) {
128 
129                 min = (float) p2.y;
130                 max = (float) p1.y;
131             } else {
132 
133                 min = (float) p1.y;
134                 max = (float) p2.y;
135             }
136 
137             MPPointD.recycleInstance(p1);
138             MPPointD.recycleInstance(p2);
139         }
140 
141         computeAxisValues(min, max);
142     }
143 
144     /**
145      * Sets up the axis values. Computes the desired number of labels between the two given extremes.
146      *
147      * @return
148      */
computeAxisValues(float min, float max)149     protected void computeAxisValues(float min, float max) {
150 
151         float yMin = min;
152         float yMax = max;
153 
154         int labelCount = mAxis.getLabelCount();
155         double range = Math.abs(yMax - yMin);
156 
157         if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
158             mAxis.mEntries = new float[]{};
159             mAxis.mCenteredEntries = new float[]{};
160             mAxis.mEntryCount = 0;
161             return;
162         }
163 
164         // Find out how much spacing (in y value space) between axis values
165         double rawInterval = range / labelCount;
166         double interval = Utils.roundToNextSignificant(rawInterval);
167 
168         // If granularity is enabled, then do not allow the interval to go below specified granularity.
169         // This is used to avoid repeated values when rounding values for display.
170         if (mAxis.isGranularityEnabled())
171             interval = interval < mAxis.getGranularity() ? mAxis.getGranularity() : interval;
172 
173         // Normalize interval
174         double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
175         int intervalSigDigit = (int) (interval / intervalMagnitude);
176         if (intervalSigDigit > 5) {
177             // Use one order of magnitude higher, to avoid intervals like 0.9 or 90
178             // if it's 0.0 after floor(), we use the old value
179             interval = Math.floor(10.0 * intervalMagnitude) == 0.0
180                     ? interval
181                     : Math.floor(10.0 * intervalMagnitude);
182 
183         }
184 
185         int n = mAxis.isCenterAxisLabelsEnabled() ? 1 : 0;
186 
187         // force label count
188         if (mAxis.isForceLabelsEnabled()) {
189 
190             interval = (float) range / (float) (labelCount - 1);
191             mAxis.mEntryCount = labelCount;
192 
193             if (mAxis.mEntries.length < labelCount) {
194                 // Ensure stops contains at least numStops elements.
195                 mAxis.mEntries = new float[labelCount];
196             }
197 
198             float v = min;
199 
200             for (int i = 0; i < labelCount; i++) {
201                 mAxis.mEntries[i] = v;
202                 v += interval;
203             }
204 
205             n = labelCount;
206 
207             // no forced count
208         } else {
209 
210             double first = interval == 0.0 ? 0.0 : Math.ceil(yMin / interval) * interval;
211             if(mAxis.isCenterAxisLabelsEnabled()) {
212                 first -= interval;
213             }
214 
215             double last = interval == 0.0 ? 0.0 : Utils.nextUp(Math.floor(yMax / interval) * interval);
216 
217             double f;
218             int i;
219 
220             if (interval != 0.0 && last != first) {
221                 for (f = first; f <= last; f += interval) {
222                     ++n;
223                 }
224             }
225             else if (last == first && n == 0) {
226                 n = 1;
227             }
228 
229             mAxis.mEntryCount = n;
230 
231             if (mAxis.mEntries.length < n) {
232                 // Ensure stops contains at least numStops elements.
233                 mAxis.mEntries = new float[n];
234             }
235 
236             for (f = first, i = 0; i < n; f += interval, ++i) {
237 
238                 if (f == 0.0) // Fix for negative zero case (Where value == -0.0, and 0.0 == -0.0)
239                     f = 0.0;
240 
241                 mAxis.mEntries[i] = (float) f;
242             }
243         }
244 
245         // set decimals
246         if (interval < 1) {
247             mAxis.mDecimals = (int) Math.ceil(-Math.log10(interval));
248         } else {
249             mAxis.mDecimals = 0;
250         }
251 
252         if (mAxis.isCenterAxisLabelsEnabled()) {
253 
254             if (mAxis.mCenteredEntries.length < n) {
255                 mAxis.mCenteredEntries = new float[n];
256             }
257 
258             float offset = (float)interval / 2f;
259 
260             for (int i = 0; i < n; i++) {
261                 mAxis.mCenteredEntries[i] = mAxis.mEntries[i] + offset;
262             }
263         }
264     }
265 
266     /**
267      * Draws the axis labels to the screen.
268      *
269      * @param c
270      */
renderAxisLabels(Canvas c)271     public abstract void renderAxisLabels(Canvas c);
272 
273     /**
274      * Draws the grid lines belonging to the axis.
275      *
276      * @param c
277      */
renderGridLines(Canvas c)278     public abstract void renderGridLines(Canvas c);
279 
280     /**
281      * Draws the line that goes alongside the axis.
282      *
283      * @param c
284      */
renderAxisLine(Canvas c)285     public abstract void renderAxisLine(Canvas c);
286 
287     /**
288      * Draws the LimitLines associated with this axis to the screen.
289      *
290      * @param c
291      */
renderLimitLines(Canvas c)292     public abstract void renderLimitLines(Canvas c);
293 }
294