• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 AndroidPlot.com
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 
17 package com.androidplot.xy;
18 
19 import android.graphics.*;
20 
21 import com.androidplot.exception.PlotRenderException;
22 import com.androidplot.ui.LayoutManager;
23 import com.androidplot.ui.SizeMetrics;
24 import com.androidplot.ui.widget.Widget;
25 import com.androidplot.util.FontUtils;
26 import com.androidplot.util.ValPixConverter;
27 import com.androidplot.util.ZHash;
28 import com.androidplot.util.ZIndexable;
29 
30 import java.text.DecimalFormat;
31 import java.text.Format;
32 
33 /**
34  * Displays graphical data annotated with domain and range tick markers.
35  */
36 public class XYGraphWidget extends Widget {
37 
getRangeLabelOrientation()38     public float getRangeLabelOrientation() {
39         return rangeLabelOrientation;
40     }
41 
setRangeLabelOrientation(float rangeLabelOrientation)42     public void setRangeLabelOrientation(float rangeLabelOrientation) {
43         this.rangeLabelOrientation = rangeLabelOrientation;
44     }
45 
getDomainLabelOrientation()46     public float getDomainLabelOrientation() {
47         return domainLabelOrientation;
48     }
49 
setDomainLabelOrientation(float domainLabelOrientation)50     public void setDomainLabelOrientation(float domainLabelOrientation) {
51         this.domainLabelOrientation = domainLabelOrientation;
52     }
53 
54     /**
55      * Will be used in a future version.
56      */
57     public enum XYPlotOrientation {
58         HORIZONTAL, VERTICAL
59     }
60 
61     private static final int MARKER_LABEL_SPACING = 2;
62     private static final int CURSOR_LABEL_SPACING = 2; // space between cursor
63     private static final String TAG = "AndroidPlot";
64                                                        // lines and label in
65                                                        // pixels
66     private float domainLabelWidth = 15; // how many pixels is the area
67                                          // allocated for domain labels
68     private float rangeLabelWidth = 41; // ...
69     private float domainLabelVerticalOffset = -5;
70     private float domainLabelHorizontalOffset = 0.0f;
71     private float rangeLabelHorizontalOffset = 1.0f;   // allows tweaking of text position
72     private float rangeLabelVerticalOffset = 0.0f;  // allows tweaking of text position
73 
74     private int ticksPerRangeLabel = 1;
75     private int ticksPerDomainLabel = 1;
76     private float gridPaddingTop = 0;
77     private float gridPaddingBottom = 0;
78     private float gridPaddingLeft = 0;
79     private float gridPaddingRight = 0;
80     private int domainLabelTickExtension = 5;
81     private int rangeLabelTickExtension = 5;
82     private Paint gridBackgroundPaint;
83     private Paint rangeGridLinePaint;
84     private Paint rangeSubGridLinePaint;
85     private Paint domainGridLinePaint;
86     private Paint domainSubGridLinePaint;
87     private Paint domainLabelPaint;
88     private Paint rangeLabelPaint;
89     private Paint domainCursorPaint;
90     private Paint rangeCursorPaint;
91     private Paint cursorLabelPaint;
92     private Paint cursorLabelBackgroundPaint;
93     private XYPlot plot;
94     private Format rangeValueFormat;
95     private Format domainValueFormat;
96     private Paint domainOriginLinePaint;
97     private Paint rangeOriginLinePaint;
98     private Paint domainOriginLabelPaint;
99     private Paint rangeOriginLabelPaint;
100     private RectF gridRect;
101     private RectF paddedGridRect;
102     private float domainCursorPosition;
103     private float rangeCursorPosition;
104     @SuppressWarnings("FieldCanBeLocal")
105     private boolean drawCursorLabelEnabled = true;
106     private boolean drawMarkersEnabled = true;
107 
108     private boolean rangeAxisLeft = true;
109     private boolean domainAxisBottom = true;
110 
111     private float rangeLabelOrientation;
112     private float domainLabelOrientation;
113 
114     // TODO: consider typing this manager with a special
115     // axisLabelRegionFormatter
116     // private ZHash<LineRegion, AxisValueLabelFormatter> domainLabelRegions;
117     // private ZHash<LineRegion, AxisValueLabelFormatter> rangeLabelRegions;
118     private ZHash<RectRegion, AxisValueLabelFormatter> axisValueLabelRegions;
119 
120     {
121         gridBackgroundPaint = new Paint();
122         gridBackgroundPaint.setColor(Color.rgb(140, 140, 140));
123         gridBackgroundPaint.setStyle(Paint.Style.FILL);
124         rangeGridLinePaint = new Paint();
125         rangeGridLinePaint.setColor(Color.rgb(180, 180, 180));
126         rangeGridLinePaint.setAntiAlias(true);
127         rangeGridLinePaint.setStyle(Paint.Style.STROKE);
128         domainGridLinePaint = new Paint(rangeGridLinePaint);
129         domainSubGridLinePaint = new Paint(domainGridLinePaint);
130         rangeSubGridLinePaint = new Paint(rangeGridLinePaint);
131         domainOriginLinePaint = new Paint();
132         domainOriginLinePaint.setColor(Color.WHITE);
133         domainOriginLinePaint.setAntiAlias(true);
134         rangeOriginLinePaint = new Paint();
135         rangeOriginLinePaint.setColor(Color.WHITE);
136         rangeOriginLinePaint.setAntiAlias(true);
137         domainOriginLabelPaint = new Paint();
138         domainOriginLabelPaint.setColor(Color.WHITE);
139         domainOriginLabelPaint.setAntiAlias(true);
140         domainOriginLabelPaint.setTextAlign(Paint.Align.CENTER);
141         rangeOriginLabelPaint = new Paint();
142         rangeOriginLabelPaint.setColor(Color.WHITE);
143         rangeOriginLabelPaint.setAntiAlias(true);
144         rangeOriginLabelPaint.setTextAlign(Paint.Align.RIGHT);
145         domainLabelPaint = new Paint();
146         domainLabelPaint.setColor(Color.LTGRAY);
147         domainLabelPaint.setAntiAlias(true);
148         domainLabelPaint.setTextAlign(Paint.Align.CENTER);
149         rangeLabelPaint = new Paint();
150         rangeLabelPaint.setColor(Color.LTGRAY);
151         rangeLabelPaint.setAntiAlias(true);
152         rangeLabelPaint.setTextAlign(Paint.Align.RIGHT);
153         domainCursorPaint = new Paint();
154         domainCursorPaint.setColor(Color.YELLOW);
155         rangeCursorPaint = new Paint();
156         rangeCursorPaint.setColor(Color.YELLOW);
157         cursorLabelPaint = new Paint();
158         cursorLabelPaint.setColor(Color.YELLOW);
159         cursorLabelBackgroundPaint = new Paint();
160         cursorLabelBackgroundPaint.setColor(Color.argb(100, 50, 50, 50));
161         setMarginTop(7);
162         setMarginRight(4);
163         setMarginBottom(4);
164         rangeValueFormat = new DecimalFormat("0.0");
165         domainValueFormat = new DecimalFormat("0.0");
166         // domainLabelRegions = new ZHash<LineRegion,
167         // AxisValueLabelFormatter>();
168         // rangeLabelRegions = new ZHash<LineRegion, AxisValueLabelFormatter>();
169         axisValueLabelRegions = new ZHash<RectRegion, AxisValueLabelFormatter>();
170     }
171 
XYGraphWidget(LayoutManager layoutManager, XYPlot plot, SizeMetrics sizeMetrics)172     public XYGraphWidget(LayoutManager layoutManager, XYPlot plot, SizeMetrics sizeMetrics) {
173         super(layoutManager, sizeMetrics);
174         this.plot = plot;
175     }
176 
getAxisValueLabelRegions()177     public ZIndexable<RectRegion> getAxisValueLabelRegions() {
178         return axisValueLabelRegions;
179     }
180 
181     /**
182      * Add a new Region used for rendering axis valuelabels. Note that it is
183      * possible to add multiple Region instances which overlap, in which cast
184      * the last region to be added will be used. It is up to the developer to
185      * guard against this often undesireable situation.
186      *
187      * @param region
188      * @param formatter
189      */
addAxisValueLabelRegion(RectRegion region, AxisValueLabelFormatter formatter)190     public void addAxisValueLabelRegion(RectRegion region,
191             AxisValueLabelFormatter formatter) {
192         axisValueLabelRegions.addToTop(region, formatter);
193     }
194 
195     /**
196      * Convenience method - wraps addAxisValueLabelRegion, using
197      * Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY to mask off range
198      * axis value labels.
199      *
200      * @param min
201      * @param max
202      * @param formatter
203      *
204      */
addDomainAxisValueLabelRegion(double min, double max, AxisValueLabelFormatter formatter)205     public void addDomainAxisValueLabelRegion(double min, double max,
206             AxisValueLabelFormatter formatter) {
207         addAxisValueLabelRegion(new RectRegion(min, max,
208                 Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, null),
209                 formatter);
210     }
211 
212     /**
213      * Convenience method - wraps addAxisValueLabelRegion, using
214      * Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY to mask off domain
215      * axis value labels.
216      *
217      * @param min
218      * @param max
219      * @param formatter
220      */
addRangeAxisValueLabelRegion(double min, double max, AxisValueLabelFormatter formatter)221     public void addRangeAxisValueLabelRegion(double min, double max,
222             AxisValueLabelFormatter formatter) {
223         addAxisValueLabelRegion(new RectRegion(Double.POSITIVE_INFINITY,
224                 Double.NEGATIVE_INFINITY, min, max, null), formatter);
225     }
226 
227     /*
228      * public void addRangeLabelRegion(LineRegion region,
229      * AxisValueLabelFormatter formatter) { rangeLabelRegions.addToTop(region,
230      * formatter); }
231      *
232      * public boolean removeRangeLabelRegion(LineRegion region) { return
233      * rangeLabelRegions.remove(region); }
234      */
235 
236     /**
237      * Returns the formatter associated with the first (bottom) Region
238      * containing x and y.
239      *
240      * @param x
241      * @param y
242      * @return the formatter associated with the first (bottom) region
243      *         containing x and y. null otherwise.
244      */
getAxisValueLabelFormatterForVal(double x, double y)245     public AxisValueLabelFormatter getAxisValueLabelFormatterForVal(double x,
246             double y) {
247         for (RectRegion r : axisValueLabelRegions.elements()) {
248             if (r.containsValue(x, y)) {
249                 return axisValueLabelRegions.get(r);
250             }
251         }
252         return null;
253     }
254 
getAxisValueLabelFormatterForDomainVal( double val)255     public AxisValueLabelFormatter getAxisValueLabelFormatterForDomainVal(
256             double val) {
257         for (RectRegion r : axisValueLabelRegions.elements()) {
258             if (r.containsDomainValue(val)) {
259                 return axisValueLabelRegions.get(r);
260             }
261         }
262         return null;
263     }
264 
getAxisValueLabelFormatterForRangeVal( double val)265     public AxisValueLabelFormatter getAxisValueLabelFormatterForRangeVal(
266             double val) {
267         for (RectRegion r : axisValueLabelRegions.elements()) {
268             if (r.containsRangeValue(val)) {
269                 return axisValueLabelRegions.get(r);
270             }
271         }
272         return null;
273     }
274 
275     /**
276      * Returns the formatter associated with the first (bottom-most) Region
277      * containing value.
278      *
279      * @param value
280      * @return
281      */
282     /*
283      * public AxisValueLabelFormatter getXYAxisFormatterForRangeVal(double
284      * value) { return getRegionContainingVal(rangeLabelRegions, value); }
285      *//**
286      * Returns the formatter associated with the first (bottom-most) Region
287      * containing value.
288      *
289      * @param value
290      * @return
291      */
292     /*
293      * public AxisValueLabelFormatter getXYAxisFormatterForDomainVal(double
294      * value) { return getRegionContainingVal(domainLabelRegions, value); }
295      */
296 
297     /*
298      * private AxisValueLabelFormatter getRegionContainingVal(ZHash<LineRegion,
299      * AxisValueLabelFormatter> zhash, double val) { for (LineRegion r :
300      * zhash.elements()) { if (r.contains(val)) { return
301      * rangeLabelRegions.get(r); } } // nothing found return null; }
302      */
303 
304     /**
305      * Returns a RectF representing the grid area last drawn by this plot.
306      *
307      * @return
308      */
getGridRect()309     public RectF getGridRect() {
310         return paddedGridRect;
311     }
getFormattedRangeValue(Number value)312     private String getFormattedRangeValue(Number value) {
313         return rangeValueFormat.format(value);
314     }
315 
getFormattedDomainValue(Number value)316     private String getFormattedDomainValue(Number value) {
317         return domainValueFormat.format(value);
318     }
319 
320     /**
321      * Convenience method. Wraps getYVal(float)
322      *
323      * @param point
324      * @return
325      */
getYVal(PointF point)326     public Double getYVal(PointF point) {
327         return getYVal(point.y);
328     }
329 
330     /**
331      * Converts a y pixel to a y value.
332      *
333      * @param yPix
334      * @return
335      */
getYVal(float yPix)336     public Double getYVal(float yPix) {
337         if (plot.getCalculatedMinY() == null
338                 || plot.getCalculatedMaxY() == null) {
339             return null;
340         }
341         return ValPixConverter.pixToVal(yPix - paddedGridRect.top, plot
342                 .getCalculatedMinY().doubleValue(), plot.getCalculatedMaxY()
343                 .doubleValue(), paddedGridRect.height(), true);
344     }
345 
346     /**
347      * Convenience method. Wraps getXVal(float)
348      *
349      * @param point
350      * @return
351      */
getXVal(PointF point)352     public Double getXVal(PointF point) {
353         return getXVal(point.x);
354     }
355 
356     /**
357      * Converts an x pixel into an x value.
358      *
359      * @param xPix
360      * @return
361      */
getXVal(float xPix)362     public Double getXVal(float xPix) {
363         if (plot.getCalculatedMinX() == null
364                 || plot.getCalculatedMaxX() == null) {
365             return null;
366         }
367         return ValPixConverter.pixToVal(xPix - paddedGridRect.left, plot
368                 .getCalculatedMinX().doubleValue(), plot.getCalculatedMaxX()
369                 .doubleValue(), paddedGridRect.width(), false);
370     }
371 
372     @Override
doOnDraw(Canvas canvas, RectF widgetRect)373     protected void doOnDraw(Canvas canvas, RectF widgetRect)
374             throws PlotRenderException {
375         gridRect = getGridRect(widgetRect); // used for drawing the background
376                                             // of the grid
377         paddedGridRect = getPaddedGridRect(gridRect); // used for drawing lines
378                                                       // etc.
379         //Log.v(TAG, "gridRect :" + gridRect);
380         //Log.v(TAG, "paddedGridRect :" + paddedGridRect);
381         // if (!plot.isEmpty()) {
382         // don't draw if we have no space to draw into
383         if ((paddedGridRect.height() > 0.0f) && (paddedGridRect.width() > 0.0f)) {
384             if (plot.getCalculatedMinX() != null
385                     && plot.getCalculatedMaxX() != null
386                     && plot.getCalculatedMinY() != null
387                     && plot.getCalculatedMaxY() != null) {
388                 drawGrid(canvas);
389                 drawData(canvas);
390                 drawCursors(canvas);
391                 if (isDrawMarkersEnabled()) {
392                     drawMarkers(canvas);
393                 }
394             }
395         }
396         // }
397     }
398 
getGridRect(RectF widgetRect)399     private RectF getGridRect(RectF widgetRect) {
400         return new RectF(widgetRect.left + ((rangeAxisLeft)?rangeLabelWidth:1),
401                 widgetRect.top + ((domainAxisBottom)?1:domainLabelWidth),
402                 widgetRect.right - ((rangeAxisLeft)?1:rangeLabelWidth),
403                 widgetRect.bottom - ((domainAxisBottom)?domainLabelWidth:1));
404     }
405 
getPaddedGridRect(RectF gridRect)406     private RectF getPaddedGridRect(RectF gridRect) {
407         return new RectF(gridRect.left + gridPaddingLeft, gridRect.top
408                 + gridPaddingTop, gridRect.right - gridPaddingRight,
409                 gridRect.bottom - gridPaddingBottom);
410     }
411 
drawTickText(Canvas canvas, XYAxisType axis, Number value, float xPix, float yPix, Paint labelPaint)412     private void drawTickText(Canvas canvas, XYAxisType axis, Number value,
413             float xPix, float yPix, Paint labelPaint) {
414         AxisValueLabelFormatter rf = null;
415         String txt = null;
416         double v = value.doubleValue();
417 
418         int canvasState = canvas.save();
419         try {
420             switch (axis) {
421                 case DOMAIN:
422                     rf = getAxisValueLabelFormatterForDomainVal(v);
423                     txt = getFormattedDomainValue(value);
424                     canvas.rotate(getDomainLabelOrientation(), xPix, yPix);
425                     break;
426                 case RANGE:
427                     rf = getAxisValueLabelFormatterForRangeVal(v);
428                     txt = getFormattedRangeValue(value);
429                     canvas.rotate(getRangeLabelOrientation(), xPix, yPix);
430                     break;
431             }
432 
433             // if a matching region formatter was found, create a clone
434             // of labelPaint and use the formatter's color. Otherwise
435             // just use labelPaint:
436             Paint p;
437             if (rf != null) {
438                 // p = rf.getPaint();
439                 p = new Paint(labelPaint);
440                 p.setColor(rf.getColor());
441                 // p.setColor(Color.RED);
442             } else {
443                 p = labelPaint;
444             }
445             canvas.drawText(txt, xPix, yPix, p);
446         } finally {
447             canvas.restoreToCount(canvasState);
448         }
449     }
450 
drawDomainTick(Canvas canvas, float xPix, Number xVal, Paint labelPaint, Paint linePaint, boolean drawLineOnly)451     private void drawDomainTick(Canvas canvas, float xPix, Number xVal,
452             Paint labelPaint, Paint linePaint, boolean drawLineOnly) {
453         if (!drawLineOnly) {
454             if (linePaint != null) {
455                 if (domainAxisBottom){
456                 canvas.drawLine(xPix, gridRect.top, xPix, gridRect.bottom
457                         + domainLabelTickExtension, linePaint);
458                 } else {
459                     canvas.drawLine(xPix, gridRect.top - domainLabelTickExtension, xPix,
460                             gridRect.bottom , linePaint);
461                 }
462             }
463             if (labelPaint != null) {
464                 float fontHeight = FontUtils.getFontHeight(labelPaint);
465                 float yPix;
466                 if (domainAxisBottom){
467                     yPix = gridRect.bottom + domainLabelTickExtension
468                             + domainLabelVerticalOffset + fontHeight;
469                 } else {
470                     yPix = gridRect.top - domainLabelTickExtension
471                             - domainLabelVerticalOffset;
472                 }
473                 drawTickText(canvas, XYAxisType.DOMAIN, xVal, xPix + domainLabelHorizontalOffset, yPix,
474                         labelPaint);
475             }
476         } else if (linePaint != null) {
477 
478             canvas.drawLine(xPix, gridRect.top, xPix, gridRect.bottom,
479                     linePaint);
480 
481         }
482     }
483 
drawRangeTick(Canvas canvas, float yPix, Number yVal, Paint labelPaint, Paint linePaint, boolean drawLineOnly)484     public void drawRangeTick(Canvas canvas, float yPix, Number yVal,
485             Paint labelPaint, Paint linePaint, boolean drawLineOnly) {
486         if (!drawLineOnly) {
487             if (linePaint != null) {
488                 if (rangeAxisLeft){
489                 canvas.drawLine(gridRect.left - rangeLabelTickExtension, yPix,
490                         gridRect.right, yPix, linePaint);
491                 } else {
492                     canvas.drawLine(gridRect.left, yPix,
493                             gridRect.right + rangeLabelTickExtension, yPix, linePaint);
494                 }
495             }
496             if (labelPaint != null) {
497                 float xPix;
498                 if (rangeAxisLeft){
499                     xPix = gridRect.left
500                             - (rangeLabelTickExtension + rangeLabelHorizontalOffset);
501                 } else {
502                     xPix = gridRect.right
503                             + (rangeLabelTickExtension + rangeLabelHorizontalOffset);
504                 }
505                 drawTickText(canvas, XYAxisType.RANGE, yVal, xPix, yPix - rangeLabelVerticalOffset,
506                         labelPaint);
507             }
508         } else if (linePaint != null) {
509             canvas.drawLine(gridRect.left, yPix, gridRect.right, yPix,
510                     linePaint);
511         }
512     }
513 
514     /**
515      * Draws the drid and domain/range labels for the plot.
516      *
517      * @param canvas
518      */
drawGrid(Canvas canvas)519     protected void drawGrid(Canvas canvas) {
520 
521         if (gridBackgroundPaint != null) {
522             canvas.drawRect(gridRect, gridBackgroundPaint);
523         }
524 
525         float domainOriginF;
526         if (plot.getDomainOrigin() != null) {
527             double domainOriginVal = plot.getDomainOrigin().doubleValue();
528             domainOriginF = ValPixConverter.valToPix(domainOriginVal, plot
529                     .getCalculatedMinX().doubleValue(), plot
530                     .getCalculatedMaxX().doubleValue(), paddedGridRect.width(),
531                     false);
532             domainOriginF += paddedGridRect.left;
533             // if no origin is set, use the leftmost value visible on the grid:
534         } else {
535             domainOriginF = paddedGridRect.left;
536         }
537 
538         XYStep domainStep = XYStepCalculator.getStep(plot, XYAxisType.DOMAIN,
539                 paddedGridRect, plot.getCalculatedMinX().doubleValue(), plot
540                         .getCalculatedMaxX().doubleValue());
541 
542         // draw domain origin:
543         if (domainOriginF >= paddedGridRect.left
544                 && domainOriginF <= paddedGridRect.right) {
545             if (domainOriginLinePaint != null){
546                 domainOriginLinePaint.setTextAlign(Paint.Align.CENTER);
547             }
548             drawDomainTick(canvas, domainOriginF, plot.getDomainOrigin()
549                     .doubleValue(), domainOriginLabelPaint,
550                     domainOriginLinePaint, false);
551         }
552 
553         // draw ticks LEFT of origin:
554         {
555             int i = 1;
556             double xVal;
557             float xPix = domainOriginF - domainStep.getStepPix();
558             for (; xPix >= paddedGridRect.left; xPix = domainOriginF
559                     - (i * domainStep.getStepPix())) {
560                 xVal = plot.getDomainOrigin().doubleValue() - i
561                         * domainStep.getStepVal();
562                 if (xPix >= paddedGridRect.left && xPix <= paddedGridRect.right) {
563                     if (i % getTicksPerDomainLabel() == 0) {
564                         drawDomainTick(canvas, xPix, xVal, domainLabelPaint,
565                                 domainGridLinePaint, false);
566                     } else {
567                         drawDomainTick(canvas, xPix, xVal, domainLabelPaint,
568                                 domainSubGridLinePaint, true);
569                     }
570                 }
571                 i++;
572             }
573         }
574 
575         // draw ticks RIGHT of origin:
576         {
577             int i = 1;
578             double xVal;
579             float xPix = domainOriginF + domainStep.getStepPix();
580             for (; xPix <= paddedGridRect.right; xPix = domainOriginF
581                     + (i * domainStep.getStepPix())) {
582                 xVal = plot.getDomainOrigin().doubleValue() + i
583                         * domainStep.getStepVal();
584                 if (xPix >= paddedGridRect.left && xPix <= paddedGridRect.right) {
585 
586                     if (i % getTicksPerDomainLabel() == 0) {
587                         drawDomainTick(canvas, xPix, xVal, domainLabelPaint,
588                                 domainGridLinePaint, false);
589                     } else {
590                         drawDomainTick(canvas, xPix, xVal, domainLabelPaint,
591                                 domainSubGridLinePaint, true);
592                     }
593                 }
594                 i++;
595             }
596         }
597 
598         // draw range origin:
599 
600         float rangeOriginF;
601         if (plot.getRangeOrigin() != null) {
602             // --------- NEW WAY ------
603             double rangeOriginD = plot.getRangeOrigin().doubleValue();
604             rangeOriginF = ValPixConverter.valToPix(rangeOriginD, plot
605                     .getCalculatedMinY().doubleValue(), plot
606                     .getCalculatedMaxY().doubleValue(),
607                     paddedGridRect.height(), true);
608             rangeOriginF += paddedGridRect.top;
609             // if no origin is set, use the leftmost value visible on the grid
610         } else {
611             rangeOriginF = paddedGridRect.bottom;
612         }
613 
614         XYStep rangeStep = XYStepCalculator.getStep(plot, XYAxisType.RANGE,
615                 paddedGridRect, plot.getCalculatedMinY().doubleValue(), plot
616                         .getCalculatedMaxY().doubleValue());
617 
618         // draw range origin:
619         if (rangeOriginF >= paddedGridRect.top
620                 && rangeOriginF <= paddedGridRect.bottom) {
621             if (rangeOriginLinePaint != null){
622                 rangeOriginLinePaint.setTextAlign(Paint.Align.RIGHT);
623             }
624             drawRangeTick(canvas, rangeOriginF, plot.getRangeOrigin()
625                     .doubleValue(), rangeOriginLabelPaint,
626                     rangeOriginLinePaint, false);
627         }
628         // draw ticks ABOVE origin:
629         {
630             int i = 1;
631             double yVal;
632             float yPix = rangeOriginF - rangeStep.getStepPix();
633             for (; yPix >= paddedGridRect.top; yPix = rangeOriginF
634                     - (i * rangeStep.getStepPix())) {
635                 yVal = plot.getRangeOrigin().doubleValue() + i
636                         * rangeStep.getStepVal();
637                 if (yPix >= paddedGridRect.top && yPix <= paddedGridRect.bottom) {
638                     if (i % getTicksPerRangeLabel() == 0) {
639                         drawRangeTick(canvas, yPix, yVal, rangeLabelPaint,
640                                 rangeGridLinePaint, false);
641                     } else {
642                         drawRangeTick(canvas, yPix, yVal, rangeLabelPaint,
643                                 rangeSubGridLinePaint, true);
644                     }
645                 }
646                 i++;
647             }
648         }
649 
650         // draw ticks BENEATH origin:
651         {
652             int i = 1;
653             double yVal;
654             float yPix = rangeOriginF + rangeStep.getStepPix();
655             for (; yPix <= paddedGridRect.bottom; yPix = rangeOriginF
656                     + (i * rangeStep.getStepPix())) {
657                 yVal = plot.getRangeOrigin().doubleValue() - i
658                         * rangeStep.getStepVal();
659                 if (yPix >= paddedGridRect.top && yPix <= paddedGridRect.bottom) {
660                     if (i % getTicksPerRangeLabel() == 0) {
661                         drawRangeTick(canvas, yPix, yVal, rangeLabelPaint,
662                                 rangeGridLinePaint, false);
663                     } else {
664                         drawRangeTick(canvas, yPix, yVal, rangeLabelPaint,
665                                 rangeSubGridLinePaint, true);
666                     }
667                 }
668                 i++;
669             }
670         }
671     }
672 
673     /**
674      * Renders the text associated with user defined markers
675      *
676      * @param canvas
677      * @param text
678      * @param marker
679      * @param x
680      * @param y
681      */
drawMarkerText(Canvas canvas, String text, ValueMarker marker, float x, float y)682     private void drawMarkerText(Canvas canvas, String text, ValueMarker marker,
683             float x, float y) {
684         x += MARKER_LABEL_SPACING;
685         y -= MARKER_LABEL_SPACING;
686         RectF textRect = new RectF(FontUtils.getStringDimensions(text,
687                 marker.getTextPaint()));
688         textRect.offsetTo(x, y - textRect.height());
689 
690         if (textRect.right > paddedGridRect.right) {
691             textRect.offset(-(textRect.right - paddedGridRect.right), 0);
692         }
693 
694         if (textRect.top < paddedGridRect.top) {
695             textRect.offset(0, paddedGridRect.top - textRect.top);
696         }
697 
698         canvas.drawText(text, textRect.left, textRect.bottom,
699                 marker.getTextPaint());
700 
701     }
702 
drawMarkers(Canvas canvas)703     protected void drawMarkers(Canvas canvas) {
704         for (YValueMarker marker : plot.getYValueMarkers()) {
705 
706             if (marker.getValue() != null) {
707                 double yVal = marker.getValue().doubleValue();
708                 float yPix = ValPixConverter.valToPix(yVal, plot
709                         .getCalculatedMinY().doubleValue(), plot
710                         .getCalculatedMaxY().doubleValue(), paddedGridRect
711                         .height(), true);
712                 yPix += paddedGridRect.top;
713                 canvas.drawLine(paddedGridRect.left, yPix,
714                         paddedGridRect.right, yPix, marker.getLinePaint());
715 
716                 // String text = getFormattedRangeValue(yVal);
717                 float xPix = marker.getTextPosition().getPixelValue(
718                         paddedGridRect.width());
719                 xPix += paddedGridRect.left;
720 
721                 if (marker.getText() != null) {
722                     drawMarkerText(canvas, marker.getText(), marker, xPix, yPix);
723                 } else {
724                     drawMarkerText(canvas,
725                             getFormattedRangeValue(marker.getValue()), marker,
726                             xPix, yPix);
727                 }
728             }
729         }
730 
731         for (XValueMarker marker : plot.getXValueMarkers()) {
732             if (marker.getValue() != null) {
733                 double xVal = marker.getValue().doubleValue();
734                 float xPix = ValPixConverter.valToPix(xVal, plot
735                         .getCalculatedMinX().doubleValue(), plot
736                         .getCalculatedMaxX().doubleValue(), paddedGridRect
737                         .width(), false);
738                 xPix += paddedGridRect.left;
739                 canvas.drawLine(xPix, paddedGridRect.top, xPix,
740                         paddedGridRect.bottom, marker.getLinePaint());
741 
742                 // String text = getFormattedDomainValue(xVal);
743                 float yPix = marker.getTextPosition().getPixelValue(
744                         paddedGridRect.height());
745                 yPix += paddedGridRect.top;
746                 if (marker.getText() != null) {
747                     drawMarkerText(canvas, marker.getText(), marker, xPix, yPix);
748                 } else {
749                     drawMarkerText(canvas,
750                             getFormattedDomainValue(marker.getValue()), marker,
751                             xPix, yPix);
752                 }
753             }
754         }
755     }
756 
drawCursors(Canvas canvas)757     protected void drawCursors(Canvas canvas) {
758         boolean hasDomainCursor = false;
759         // draw the domain cursor:
760         if (domainCursorPaint != null
761                 && domainCursorPosition <= paddedGridRect.right
762                 && domainCursorPosition >= paddedGridRect.left) {
763             hasDomainCursor = true;
764             canvas.drawLine(domainCursorPosition, paddedGridRect.top,
765                     domainCursorPosition, paddedGridRect.bottom,
766                     domainCursorPaint);
767         }
768 
769         boolean hasRangeCursor = false;
770         // draw the range cursor:
771         if (rangeCursorPaint != null
772                 && rangeCursorPosition >= paddedGridRect.top
773                 && rangeCursorPosition <= paddedGridRect.bottom) {
774             hasRangeCursor = true;
775             canvas.drawLine(paddedGridRect.left, rangeCursorPosition,
776                     paddedGridRect.right, rangeCursorPosition, rangeCursorPaint);
777         }
778 
779         if (drawCursorLabelEnabled && cursorLabelPaint != null
780                 && hasRangeCursor && hasDomainCursor) {
781 
782             String label = "X="
783                     + getDomainValueFormat().format(getDomainCursorVal());
784             label += " Y=" + getRangeValueFormat().format(getRangeCursorVal());
785 
786             // convert the label dimensions rect into floating-point:
787             RectF cursorRect = new RectF(FontUtils.getPackedStringDimensions(
788                     label, cursorLabelPaint));
789             cursorRect.offsetTo(domainCursorPosition, rangeCursorPosition
790                     - cursorRect.height());
791 
792             // if we are too close to the right edge of the plot, we will move
793             // the
794             // label to the left side of our cursor:
795             if (cursorRect.right >= paddedGridRect.right) {
796                 cursorRect.offsetTo(domainCursorPosition - cursorRect.width(),
797                         cursorRect.top);
798             }
799 
800             // same thing for the top edge of the plot:
801             // dunno why but these rects can have negative values for top and
802             // bottom.
803             if (cursorRect.top <= paddedGridRect.top) {
804                 cursorRect.offsetTo(cursorRect.left, rangeCursorPosition);
805             }
806 
807             if (cursorLabelBackgroundPaint != null) {
808                 canvas.drawRect(cursorRect, cursorLabelBackgroundPaint);
809             }
810 
811             canvas.drawText(label, cursorRect.left, cursorRect.bottom,
812                     cursorLabelPaint);
813         }
814     }
815 
816     /**
817      * Draws lines and points for each element in the series.
818      *
819      * @param canvas
820      * @throws PlotRenderException
821      */
drawData(Canvas canvas)822     protected void drawData(Canvas canvas) throws PlotRenderException {
823         // TODO: iterate through a XYSeriesRenderer list
824 
825         // int canvasState = canvas.save();
826         try {
827             canvas.save();
828             canvas.clipRect(gridRect);
829             for (XYSeriesRenderer renderer : plot.getRendererList()) {
830                 renderer.render(canvas, paddedGridRect);
831             }
832             // canvas.restoreToCount(canvasState);
833         } finally {
834             canvas.restore();
835         }
836     }
837 
drawPoint(Canvas canvas, PointF point, Paint paint)838     protected void drawPoint(Canvas canvas, PointF point, Paint paint) {
839         canvas.drawPoint(point.x, point.y, paint);
840     }
841 
getDomainLabelWidth()842     public float getDomainLabelWidth() {
843         return domainLabelWidth;
844     }
845 
setDomainLabelWidth(float domainLabelWidth)846     public void setDomainLabelWidth(float domainLabelWidth) {
847         this.domainLabelWidth = domainLabelWidth;
848     }
849 
getRangeLabelWidth()850     public float getRangeLabelWidth() {
851         return rangeLabelWidth;
852     }
853 
setRangeLabelWidth(float rangeLabelWidth)854     public void setRangeLabelWidth(float rangeLabelWidth) {
855         this.rangeLabelWidth = rangeLabelWidth;
856     }
857 
getDomainLabelVerticalOffset()858     public float getDomainLabelVerticalOffset() {
859         return domainLabelVerticalOffset;
860     }
861 
setDomainLabelVerticalOffset(float domainLabelVerticalOffset)862     public void setDomainLabelVerticalOffset(float domainLabelVerticalOffset) {
863         this.domainLabelVerticalOffset = domainLabelVerticalOffset;
864     }
865 
getDomainLabelHorizontalOffset()866     public float getDomainLabelHorizontalOffset() {
867         return domainLabelHorizontalOffset;
868     }
869 
setDomainLabelHorizontalOffset(float domainLabelHorizontalOffset)870     public void setDomainLabelHorizontalOffset(float domainLabelHorizontalOffset) {
871         this.domainLabelHorizontalOffset = domainLabelHorizontalOffset;
872     }
873 
getRangeLabelHorizontalOffset()874     public float getRangeLabelHorizontalOffset() {
875         return rangeLabelHorizontalOffset;
876     }
877 
setRangeLabelHorizontalOffset(float rangeLabelHorizontalOffset)878     public void setRangeLabelHorizontalOffset(float rangeLabelHorizontalOffset) {
879         this.rangeLabelHorizontalOffset = rangeLabelHorizontalOffset;
880     }
881 
getRangeLabelVerticalOffset()882     public float getRangeLabelVerticalOffset() {
883         return rangeLabelVerticalOffset;
884     }
885 
setRangeLabelVerticalOffset(float rangeLabelVerticalOffset)886     public void setRangeLabelVerticalOffset(float rangeLabelVerticalOffset) {
887         this.rangeLabelVerticalOffset = rangeLabelVerticalOffset;
888     }
889 
getGridBackgroundPaint()890     public Paint getGridBackgroundPaint() {
891         return gridBackgroundPaint;
892     }
893 
setGridBackgroundPaint(Paint gridBackgroundPaint)894     public void setGridBackgroundPaint(Paint gridBackgroundPaint) {
895         this.gridBackgroundPaint = gridBackgroundPaint;
896     }
897 
getDomainLabelPaint()898     public Paint getDomainLabelPaint() {
899         return domainLabelPaint;
900     }
901 
setDomainLabelPaint(Paint domainLabelPaint)902     public void setDomainLabelPaint(Paint domainLabelPaint) {
903         this.domainLabelPaint = domainLabelPaint;
904     }
905 
getRangeLabelPaint()906     public Paint getRangeLabelPaint() {
907         return rangeLabelPaint;
908     }
909 
setRangeLabelPaint(Paint rangeLabelPaint)910     public void setRangeLabelPaint(Paint rangeLabelPaint) {
911         this.rangeLabelPaint = rangeLabelPaint;
912     }
913 
914     /**
915      * Get the paint used to draw the domain grid line.
916      */
getDomainGridLinePaint()917     public Paint getDomainGridLinePaint() {
918         return domainGridLinePaint;
919     }
920 
921     /**
922      * Set the paint used to draw the domain grid line.
923      * @param gridLinePaint
924      */
setDomainGridLinePaint(Paint gridLinePaint)925     public void setDomainGridLinePaint(Paint gridLinePaint) {
926         this.domainGridLinePaint = gridLinePaint;
927     }
928 
929     /**
930      * Get the paint used to draw the range grid line.
931      */
getRangeGridLinePaint()932     public Paint getRangeGridLinePaint() {
933         return rangeGridLinePaint;
934     }
935 
936     /**
937      * Get the paint used to draw the domain grid line.
938      */
getDomainSubGridLinePaint()939     public Paint getDomainSubGridLinePaint() {
940         return domainSubGridLinePaint;
941     }
942 
943     /**
944      * Set the paint used to draw the domain grid line.
945      * @param gridLinePaint
946      */
setDomainSubGridLinePaint(Paint gridLinePaint)947     public void setDomainSubGridLinePaint(Paint gridLinePaint) {
948         this.domainSubGridLinePaint = gridLinePaint;
949     }
950 
951     /**
952      * Set the Paint used to draw the range grid line.
953      * @param gridLinePaint
954      */
setRangeGridLinePaint(Paint gridLinePaint)955     public void setRangeGridLinePaint(Paint gridLinePaint) {
956         this.rangeGridLinePaint = gridLinePaint;
957     }
958 
959     /**
960      * Get the paint used to draw the range grid line.
961      */
getRangeSubGridLinePaint()962     public Paint getRangeSubGridLinePaint() {
963         return rangeSubGridLinePaint;
964     }
965 
966     /**
967      * Set the Paint used to draw the range grid line.
968      * @param gridLinePaint
969      */
setRangeSubGridLinePaint(Paint gridLinePaint)970     public void setRangeSubGridLinePaint(Paint gridLinePaint) {
971         this.rangeSubGridLinePaint = gridLinePaint;
972     }
973 
974     // TODO: make a generic renderer queue.
975 
getRangeValueFormat()976     public Format getRangeValueFormat() {
977         return rangeValueFormat;
978     }
979 
setRangeValueFormat(Format rangeValueFormat)980     public void setRangeValueFormat(Format rangeValueFormat) {
981         this.rangeValueFormat = rangeValueFormat;
982     }
983 
getDomainValueFormat()984     public Format getDomainValueFormat() {
985         return domainValueFormat;
986     }
987 
setDomainValueFormat(Format domainValueFormat)988     public void setDomainValueFormat(Format domainValueFormat) {
989         this.domainValueFormat = domainValueFormat;
990     }
991 
getDomainLabelTickExtension()992     public int getDomainLabelTickExtension() {
993         return domainLabelTickExtension;
994     }
995 
setDomainLabelTickExtension(int domainLabelTickExtension)996     public void setDomainLabelTickExtension(int domainLabelTickExtension) {
997         this.domainLabelTickExtension = domainLabelTickExtension;
998     }
999 
getRangeLabelTickExtension()1000     public int getRangeLabelTickExtension() {
1001         return rangeLabelTickExtension;
1002     }
1003 
setRangeLabelTickExtension(int rangeLabelTickExtension)1004     public void setRangeLabelTickExtension(int rangeLabelTickExtension) {
1005         this.rangeLabelTickExtension = rangeLabelTickExtension;
1006     }
1007 
getTicksPerRangeLabel()1008     public int getTicksPerRangeLabel() {
1009         return ticksPerRangeLabel;
1010     }
1011 
setTicksPerRangeLabel(int ticksPerRangeLabel)1012     public void setTicksPerRangeLabel(int ticksPerRangeLabel) {
1013         this.ticksPerRangeLabel = ticksPerRangeLabel;
1014     }
1015 
getTicksPerDomainLabel()1016     public int getTicksPerDomainLabel() {
1017         return ticksPerDomainLabel;
1018     }
1019 
setTicksPerDomainLabel(int ticksPerDomainLabel)1020     public void setTicksPerDomainLabel(int ticksPerDomainLabel) {
1021         this.ticksPerDomainLabel = ticksPerDomainLabel;
1022     }
1023 
setGridPaddingTop(float gridPaddingTop)1024     public void setGridPaddingTop(float gridPaddingTop) {
1025         this.gridPaddingTop = gridPaddingTop;
1026     }
1027 
getGridPaddingBottom()1028     public float getGridPaddingBottom() {
1029         return gridPaddingBottom;
1030     }
1031 
setGridPaddingBottom(float gridPaddingBottom)1032     public void setGridPaddingBottom(float gridPaddingBottom) {
1033         this.gridPaddingBottom = gridPaddingBottom;
1034     }
1035 
getGridPaddingLeft()1036     public float getGridPaddingLeft() {
1037         return gridPaddingLeft;
1038     }
1039 
setGridPaddingLeft(float gridPaddingLeft)1040     public void setGridPaddingLeft(float gridPaddingLeft) {
1041         this.gridPaddingLeft = gridPaddingLeft;
1042     }
1043 
getGridPaddingRight()1044     public float getGridPaddingRight() {
1045         return gridPaddingRight;
1046     }
1047 
setGridPaddingRight(float gridPaddingRight)1048     public void setGridPaddingRight(float gridPaddingRight) {
1049         this.gridPaddingRight = gridPaddingRight;
1050     }
1051 
getGridPaddingTop()1052     public float getGridPaddingTop() {
1053         return gridPaddingTop;
1054     }
1055 
setGridPadding(float left, float top, float right, float bottom)1056     public void setGridPadding(float left, float top, float right, float bottom) {
1057         setGridPaddingLeft(left);
1058         setGridPaddingTop(top);
1059         setGridPaddingRight(right);
1060         setGridPaddingBottom(bottom);
1061     }
1062 
getDomainOriginLinePaint()1063     public Paint getDomainOriginLinePaint() {
1064         return domainOriginLinePaint;
1065     }
1066 
setDomainOriginLinePaint(Paint domainOriginLinePaint)1067     public void setDomainOriginLinePaint(Paint domainOriginLinePaint) {
1068         this.domainOriginLinePaint = domainOriginLinePaint;
1069     }
1070 
getRangeOriginLinePaint()1071     public Paint getRangeOriginLinePaint() {
1072         return rangeOriginLinePaint;
1073     }
1074 
setRangeOriginLinePaint(Paint rangeOriginLinePaint)1075     public void setRangeOriginLinePaint(Paint rangeOriginLinePaint) {
1076         this.rangeOriginLinePaint = rangeOriginLinePaint;
1077     }
1078 
getDomainOriginLabelPaint()1079     public Paint getDomainOriginLabelPaint() {
1080         return domainOriginLabelPaint;
1081     }
1082 
setDomainOriginLabelPaint(Paint domainOriginLabelPaint)1083     public void setDomainOriginLabelPaint(Paint domainOriginLabelPaint) {
1084         this.domainOriginLabelPaint = domainOriginLabelPaint;
1085     }
1086 
getRangeOriginLabelPaint()1087     public Paint getRangeOriginLabelPaint() {
1088         return rangeOriginLabelPaint;
1089     }
1090 
setRangeOriginLabelPaint(Paint rangeOriginLabelPaint)1091     public void setRangeOriginLabelPaint(Paint rangeOriginLabelPaint) {
1092         this.rangeOriginLabelPaint = rangeOriginLabelPaint;
1093     }
1094 
setCursorPosition(float x, float y)1095     public void setCursorPosition(float x, float y) {
1096         setDomainCursorPosition(x);
1097         setRangeCursorPosition(y);
1098     }
1099 
setCursorPosition(PointF point)1100     public void setCursorPosition(PointF point) {
1101         setCursorPosition(point.x, point.y);
1102     }
1103 
getDomainCursorPosition()1104     public float getDomainCursorPosition() {
1105         return domainCursorPosition;
1106     }
1107 
getDomainCursorVal()1108     public Double getDomainCursorVal() {
1109         return getXVal(getDomainCursorPosition());
1110     }
1111 
setDomainCursorPosition(float domainCursorPosition)1112     public void setDomainCursorPosition(float domainCursorPosition) {
1113         this.domainCursorPosition = domainCursorPosition;
1114     }
1115 
getRangeCursorPosition()1116     public float getRangeCursorPosition() {
1117         return rangeCursorPosition;
1118     }
1119 
getRangeCursorVal()1120     public Double getRangeCursorVal() {
1121         return getYVal(getRangeCursorPosition());
1122     }
1123 
setRangeCursorPosition(float rangeCursorPosition)1124     public void setRangeCursorPosition(float rangeCursorPosition) {
1125         this.rangeCursorPosition = rangeCursorPosition;
1126     }
1127 
getCursorLabelPaint()1128     public Paint getCursorLabelPaint() {
1129         return cursorLabelPaint;
1130     }
1131 
setCursorLabelPaint(Paint cursorLabelPaint)1132     public void setCursorLabelPaint(Paint cursorLabelPaint) {
1133         this.cursorLabelPaint = cursorLabelPaint;
1134     }
1135 
getCursorLabelBackgroundPaint()1136     public Paint getCursorLabelBackgroundPaint() {
1137         return cursorLabelBackgroundPaint;
1138     }
1139 
setCursorLabelBackgroundPaint(Paint cursorLabelBackgroundPaint)1140     public void setCursorLabelBackgroundPaint(Paint cursorLabelBackgroundPaint) {
1141         this.cursorLabelBackgroundPaint = cursorLabelBackgroundPaint;
1142     }
1143 
isDrawMarkersEnabled()1144     public boolean isDrawMarkersEnabled() {
1145         return drawMarkersEnabled;
1146     }
1147 
setDrawMarkersEnabled(boolean drawMarkersEnabled)1148     public void setDrawMarkersEnabled(boolean drawMarkersEnabled) {
1149         this.drawMarkersEnabled = drawMarkersEnabled;
1150     }
1151 
isRangeAxisLeft()1152     public boolean isRangeAxisLeft() {
1153         return rangeAxisLeft;
1154     }
1155 
setRangeAxisLeft(boolean rangeAxisLeft)1156     public void setRangeAxisLeft(boolean rangeAxisLeft) {
1157         this.rangeAxisLeft = rangeAxisLeft;
1158     }
1159 
isDomainAxisBottom()1160     public boolean isDomainAxisBottom() {
1161         return domainAxisBottom;
1162     }
1163 
setDomainAxisBottom(boolean domainAxisBottom)1164     public void setDomainAxisBottom(boolean domainAxisBottom) {
1165         this.domainAxisBottom = domainAxisBottom;
1166     }
1167 
1168     /*
1169      * set the position of the range axis labels.  Set the labelPaint textSizes before setting this.
1170      * This call sets the various vertical and horizontal offsets and widths to good defaults.
1171      *
1172      * @param rangeAxisLeft axis labels are on the left hand side not the right hand side.
1173      * @param rangeAxisOverlay axis labels are overlaid on the plot, not external to it.
1174      * @param tickSize the size of the tick extensions for none overlaid axis.
1175      * @param maxLableString Sample label representing the biggest size space needs to be allocated for.
1176      */
setRangeAxisPosition(boolean rangeAxisLeft, boolean rangeAxisOverlay, int tickSize, String maxLableString)1177     public void setRangeAxisPosition(boolean rangeAxisLeft, boolean rangeAxisOverlay, int tickSize, String maxLableString){
1178         setRangeAxisLeft(rangeAxisLeft);
1179 
1180         if (rangeAxisOverlay) {
1181             setRangeLabelWidth(1);    // needs to be at least 1 to display grid line.
1182             setRangeLabelHorizontalOffset(-2.0f);
1183             setRangeLabelVerticalOffset(2.0f);    // get above the line
1184             Paint p = getRangeLabelPaint();
1185             if (p != null) {
1186                 p.setTextAlign(((rangeAxisLeft)?Paint.Align.LEFT:Paint.Align.RIGHT));
1187             }
1188             Paint po = getRangeOriginLabelPaint();
1189             if (po != null) {
1190                 po.setTextAlign(((rangeAxisLeft)?Paint.Align.LEFT:Paint.Align.RIGHT));
1191             }
1192             setRangeLabelTickExtension(0);
1193         } else {
1194             setRangeLabelWidth(1);    // needs to be at least 1 to display grid line.
1195                                       // if we have a paint this gets bigger.
1196             setRangeLabelHorizontalOffset(1.0f);
1197             setRangeLabelTickExtension(tickSize);
1198             Paint p = getRangeLabelPaint();
1199             if (p != null) {
1200                 p.setTextAlign(((!rangeAxisLeft)?Paint.Align.LEFT:Paint.Align.RIGHT));
1201                 Rect r = FontUtils.getPackedStringDimensions(maxLableString,p);
1202                 setRangeLabelVerticalOffset(r.top/2);
1203                 setRangeLabelWidth(r.right + getRangeLabelTickExtension());
1204             }
1205             Paint po = getRangeOriginLabelPaint();
1206             if (po != null) {
1207                 po.setTextAlign(((!rangeAxisLeft)?Paint.Align.LEFT:Paint.Align.RIGHT));
1208             }
1209         }
1210     }
1211 
1212     /*
1213      * set the position of the domain axis labels.  Set the labelPaint textSizes before setting this.
1214      * This call sets the various vertical and horizontal offsets and widths to good defaults.
1215      *
1216      * @param domainAxisBottom axis labels are on the bottom not the top of the plot.
1217      * @param domainAxisOverlay axis labels are overlaid on the plot, not external to it.
1218      * @param tickSize the size of the tick extensions for non overlaid axis.
1219      * @param maxLableString Sample label representing the biggest size space needs to be allocated for.
1220      */
setDomainAxisPosition(boolean domainAxisBottom, boolean domainAxisOverlay, int tickSize, String maxLabelString)1221     public void setDomainAxisPosition(boolean domainAxisBottom, boolean domainAxisOverlay, int tickSize, String maxLabelString){
1222         setDomainAxisBottom(domainAxisBottom);
1223         if (domainAxisOverlay) {
1224             setDomainLabelWidth(1);    // needs to be at least 1 to display grid line.
1225             setDomainLabelVerticalOffset(2.0f);    // get above the line
1226             setDomainLabelTickExtension(0);
1227             Paint p = getDomainLabelPaint();
1228             if (p != null) {
1229                 Rect r = FontUtils.getPackedStringDimensions(maxLabelString,p);
1230                 if (domainAxisBottom){
1231                     setDomainLabelVerticalOffset(2 * r.top);
1232                 } else {
1233                     setDomainLabelVerticalOffset(r.top - 1.0f);
1234                 }
1235             }
1236         } else {
1237             setDomainLabelWidth(1);    // needs to be at least 1 to display grid line.
1238                                        // if we have a paint this gets bigger.
1239             setDomainLabelTickExtension(tickSize);
1240             Paint p = getDomainLabelPaint();
1241             if (p != null) {
1242                 float fontHeight = FontUtils.getFontHeight(p);
1243                 if (domainAxisBottom){
1244                     setDomainLabelVerticalOffset(-4.0f);
1245                 } else {
1246                     setDomainLabelVerticalOffset(+1.0f);
1247                 }
1248                 setDomainLabelWidth(fontHeight + getDomainLabelTickExtension());
1249             }
1250         }
1251     }
1252 }
1253