Home | History | Annotate | Download | only in xy
      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.content.Context;
     20 import android.graphics.Canvas;
     21 import android.graphics.Color;
     22 import android.graphics.Paint;
     23 import android.graphics.PointF;
     24 import android.util.AttributeSet;
     25 import com.androidplot.Plot;
     26 import com.androidplot.ui.*;
     27 import com.androidplot.ui.TextOrientationType;
     28 import com.androidplot.ui.widget.TextLabelWidget;
     29 import com.androidplot.util.PixelUtils;
     30 
     31 import java.text.Format;
     32 import java.util.ArrayList;
     33 import java.util.List;
     34 
     35 /**
     36  * A View to graphically display x/y coordinates.
     37  */
     38 public class XYPlot extends Plot<XYSeries, XYSeriesFormatter, XYSeriesRenderer> {
     39 
     40     private BoundaryMode domainOriginBoundaryMode;
     41     private BoundaryMode rangeOriginBoundaryMode;
     42 
     43     // widgets
     44     private XYLegendWidget legendWidget;
     45     private XYGraphWidget graphWidget;
     46     private TextLabelWidget domainLabelWidget;
     47     private TextLabelWidget rangeLabelWidget;
     48 
     49     private XYStepMode domainStepMode = XYStepMode.SUBDIVIDE;
     50     private double domainStepValue = 10;
     51 
     52     private XYStepMode rangeStepMode = XYStepMode.SUBDIVIDE;
     53     private double rangeStepValue = 10;
     54 
     55     // user settable min/max values
     56     private Number userMinX;
     57     private Number userMaxX;
     58     private Number userMinY;
     59     private Number userMaxY;
     60 
     61     // these are the final min/max used for dispplaying data
     62     private Number calculatedMinX;
     63     private Number calculatedMaxX;
     64     private Number calculatedMinY;
     65     private Number calculatedMaxY;
     66 
     67     // previous calculated min/max vals.
     68     // primarily used for GROW/SHRINK operations.
     69     private Number prevMinX;
     70     private Number prevMaxX;
     71     private Number prevMinY;
     72     private Number prevMaxY;
     73 
     74     // uses set boundary min and max values
     75     // should be null if not used.
     76     private Number rangeTopMin = null;
     77     private Number rangeTopMax = null;
     78     private Number rangeBottomMin = null;
     79     private Number rangeBottomMax = null;
     80     private Number domainLeftMin = null;
     81     private Number domainLeftMax = null;
     82     private Number domainRightMin = null;
     83     private Number domainRightMax = null;
     84 
     85     // used for  calculating the domain/range extents that will be displayed on the plot.
     86     // using boundaries and origins are mutually exclusive.  because of this,
     87     // setting one will disable the other.  when only setting the FramingModel,
     88     // the origin or boundary is set to the current value of the plot.
     89     private XYFramingModel domainFramingModel = XYFramingModel.EDGE;
     90     private XYFramingModel rangeFramingModel = XYFramingModel.EDGE;
     91 
     92     private Number userDomainOrigin;
     93     private Number userRangeOrigin;
     94 
     95     private Number calculatedDomainOrigin;
     96     private Number calculatedRangeOrigin;
     97 
     98     @SuppressWarnings("FieldCanBeLocal")
     99     private Number domainOriginExtent = null;
    100     @SuppressWarnings("FieldCanBeLocal")
    101     private Number rangeOriginExtent = null;
    102 
    103     private BoundaryMode domainUpperBoundaryMode = BoundaryMode.AUTO;
    104     private BoundaryMode domainLowerBoundaryMode = BoundaryMode.AUTO;
    105     private BoundaryMode rangeUpperBoundaryMode = BoundaryMode.AUTO;
    106     private BoundaryMode rangeLowerBoundaryMode = BoundaryMode.AUTO;
    107 
    108     private boolean drawDomainOriginEnabled = true;
    109     private boolean drawRangeOriginEnabled = true;
    110 
    111     private ArrayList<YValueMarker> yValueMarkers;
    112     private ArrayList<XValueMarker> xValueMarkers;
    113 
    114     private RectRegion defaultBounds;
    115 
    116 
    117     private static final int DEFAULT_LEGEND_WIDGET_H_DP = 10;
    118     private static final int DEFAULT_LEGEND_WIDGET_ICON_SIZE_DP = 7;
    119     private static final int DEFAULT_GRAPH_WIDGET_H_DP = 18;
    120     private static final int DEFAULT_GRAPH_WIDGET_W_DP = 10;
    121     private static final int DEFAULT_DOMAIN_LABEL_WIDGET_H_DP = 10;
    122     private static final int DEFAULT_DOMAIN_LABEL_WIDGET_W_DP = 80;
    123     private static final int DEFAULT_RANGE_LABEL_WIDGET_H_DP = 50;
    124     private static final int DEFAULT_RANGE_LABEL_WIDGET_W_DP = 10;
    125 
    126     private static final int DEFAULT_LEGEND_WIDGET_Y_OFFSET_DP = 0;
    127     private static final int DEFAULT_LEGEND_WIDGET_X_OFFSET_DP = 40;
    128     private static final int DEFAULT_GRAPH_WIDGET_Y_OFFSET_DP = 0;
    129     private static final int DEFAULT_GRAPH_WIDGET_X_OFFSET_DP = 0;
    130     private static final int DEFAULT_DOMAIN_LABEL_WIDGET_Y_OFFSET_DP = 0;
    131     private static final int DEFAULT_DOMAIN_LABEL_WIDGET_X_OFFSET_DP = 20;
    132     private static final int DEFAULT_RANGE_LABEL_WIDGET_Y_OFFSET_DP = 0;
    133     private static final int DEFAULT_RANGE_LABEL_WIDGET_X_OFFSET_DP = 0;
    134 
    135     private static final int DEFAULT_GRAPH_WIDGET_TOP_MARGIN_DP = 3;
    136     private static final int DEFAULT_GRAPH_WIDGET_RIGHT_MARGIN_DP = 3;
    137     private static final int DEFAULT_PLOT_LEFT_MARGIN_DP = 2;
    138     private static final int DEFAULT_PLOT_RIGHT_MARGIN_DP = 2;
    139     private static final int DEFAULT_PLOT_BOTTOM_MARGIN_DP = 2;
    140 
    141     public XYPlot(Context context, String title) {
    142         super(context, title);
    143     }
    144 
    145     public XYPlot(Context context, String title, RenderMode mode) {
    146         super(context, title, mode);
    147     }
    148 
    149     public XYPlot(Context context, AttributeSet attributes) {
    150         super(context, attributes);
    151     }
    152 
    153     public XYPlot(Context context, AttributeSet attrs, int defStyle) {
    154         super(context, attrs, defStyle);
    155 
    156     }
    157 
    158     @Override
    159     protected void onPreInit() {
    160         legendWidget = new XYLegendWidget(
    161                 getLayoutManager(),
    162                 this,
    163                 new SizeMetrics(
    164                         PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_H_DP),
    165                         SizeLayoutType.ABSOLUTE, 0.5f, SizeLayoutType.RELATIVE),
    166                 new DynamicTableModel(0, 1),
    167                 new SizeMetrics(
    168                         PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_ICON_SIZE_DP),
    169                         SizeLayoutType.ABSOLUTE,
    170                         PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_ICON_SIZE_DP),
    171                         SizeLayoutType.ABSOLUTE));
    172 
    173         graphWidget = new XYGraphWidget(
    174                 getLayoutManager(),
    175                 this,
    176                 new SizeMetrics(
    177                         PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_H_DP),
    178                         SizeLayoutType.FILL,
    179                         PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_W_DP),
    180                         SizeLayoutType.FILL));
    181 
    182         Paint backgroundPaint = new Paint();
    183         backgroundPaint.setColor(Color.DKGRAY);
    184         backgroundPaint.setStyle(Paint.Style.FILL);
    185         graphWidget.setBackgroundPaint(backgroundPaint);
    186 
    187 
    188         domainLabelWidget = new TextLabelWidget(
    189                 getLayoutManager(),
    190                 new SizeMetrics(
    191                         PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_H_DP),
    192                         SizeLayoutType.ABSOLUTE,
    193                         PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_W_DP),
    194                         SizeLayoutType.ABSOLUTE),
    195                 TextOrientationType.HORIZONTAL);
    196         rangeLabelWidget = new TextLabelWidget(
    197                 getLayoutManager(),
    198                 new SizeMetrics(
    199                         PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_H_DP),
    200                         SizeLayoutType.ABSOLUTE,
    201                         PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_W_DP),
    202                         SizeLayoutType.ABSOLUTE),
    203                 TextOrientationType.VERTICAL_ASCENDING);
    204 
    205         legendWidget.position(
    206                 PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_X_OFFSET_DP),
    207                 XLayoutStyle.ABSOLUTE_FROM_RIGHT,
    208                 PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_Y_OFFSET_DP),
    209                 YLayoutStyle.ABSOLUTE_FROM_BOTTOM,
    210                 AnchorPosition.RIGHT_BOTTOM);
    211 
    212         graphWidget.position(
    213                 PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_X_OFFSET_DP),
    214                 XLayoutStyle.ABSOLUTE_FROM_RIGHT,
    215                 PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_Y_OFFSET_DP),
    216                 YLayoutStyle.ABSOLUTE_FROM_CENTER,
    217                 AnchorPosition.RIGHT_MIDDLE);
    218 
    219         domainLabelWidget.position(
    220                 PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_X_OFFSET_DP),
    221                 XLayoutStyle.ABSOLUTE_FROM_LEFT,
    222                 PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_Y_OFFSET_DP),
    223                 YLayoutStyle.ABSOLUTE_FROM_BOTTOM,
    224                 AnchorPosition.LEFT_BOTTOM);
    225 
    226         rangeLabelWidget.position(
    227                 PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_X_OFFSET_DP),
    228                 XLayoutStyle.ABSOLUTE_FROM_LEFT,
    229                 PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_Y_OFFSET_DP),
    230                 YLayoutStyle.ABSOLUTE_FROM_CENTER,
    231                 AnchorPosition.LEFT_MIDDLE);
    232 
    233         getLayoutManager().moveToTop(getTitleWidget());
    234         getLayoutManager().moveToTop(getLegendWidget());
    235         graphWidget.setMarginTop(PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_TOP_MARGIN_DP));
    236         graphWidget.setMarginRight(PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_RIGHT_MARGIN_DP));
    237 
    238         getDomainLabelWidget().pack();
    239         getRangeLabelWidget().pack();
    240         setPlotMarginLeft(PixelUtils.dpToPix(DEFAULT_PLOT_LEFT_MARGIN_DP));
    241         setPlotMarginRight(PixelUtils.dpToPix(DEFAULT_PLOT_RIGHT_MARGIN_DP));
    242         setPlotMarginBottom(PixelUtils.dpToPix(DEFAULT_PLOT_BOTTOM_MARGIN_DP));
    243 
    244         xValueMarkers = new ArrayList<XValueMarker>();
    245         yValueMarkers = new ArrayList<YValueMarker>();
    246 
    247         setDefaultBounds(new RectRegion(-1, 1, -1, 1));
    248     }
    249 
    250 
    251     public void setGridPadding(float left, float top, float right, float bottom) {
    252         getGraphWidget().setGridPaddingTop(top);
    253         getGraphWidget().setGridPaddingBottom(bottom);
    254         getGraphWidget().setGridPaddingLeft(left);
    255         getGraphWidget().setGridPaddingRight(right);
    256     }
    257 
    258     @Override
    259     protected void notifyListenersBeforeDraw(Canvas canvas) {
    260         super.notifyListenersBeforeDraw(canvas);
    261 
    262         // this call must be AFTER the notify so that if the listener
    263         // is a synchronized series, it has the opportunity to
    264         // place a read lock on it's data.
    265         calculateMinMaxVals();
    266     }
    267 
    268     /**
    269      * Checks whether the point is within the plot's graph area.
    270      *
    271      * @param x
    272      * @param y
    273      * @return
    274      */
    275     public boolean containsPoint(float x, float y) {
    276         if (getGraphWidget().getGridRect() != null) {
    277             return getGraphWidget().getGridRect().contains(x, y);
    278         }
    279         return false;
    280     }
    281 
    282 
    283     /**
    284      * Convenience method - wraps containsPoint(PointF).
    285      *
    286      * @param point
    287      * @return
    288      */
    289     public boolean containsPoint(PointF point) {
    290         return containsPoint(point.x, point.y);
    291     }
    292 
    293     public void setCursorPosition(PointF point) {
    294         getGraphWidget().setCursorPosition(point);
    295     }
    296 
    297     public void setCursorPosition(float x, float y) {
    298         getGraphWidget().setCursorPosition(x, y);
    299     }
    300 
    301     public Number getYVal(PointF point) {
    302         return getGraphWidget().getYVal(point);
    303     }
    304 
    305     public Number getXVal(PointF point) {
    306         return getGraphWidget().getXVal(point);
    307     }
    308 
    309     private boolean isXValWithinView(double xVal) {
    310         return (userMinY == null || xVal >= userMinY.doubleValue()) &&
    311                 userMaxY == null || xVal <= userMaxY.doubleValue();
    312     }
    313 
    314     private boolean isPointVisible(Number x, Number y) {
    315         // values without both an x and y val arent visible
    316         if (x == null || y == null) {
    317             return false;
    318         }
    319         return isValWithinRange(y.doubleValue(), userMinY, userMaxY) &&
    320                 isValWithinRange(x.doubleValue(), userMinX, userMaxX);
    321     }
    322 
    323     private boolean isValWithinRange(double val, Number min, Number max) {
    324         boolean isAboveMinThreshold = min == null || val >= min.doubleValue();
    325         boolean isBelowMaxThreshold = max == null || val <= max.doubleValue();
    326         return isAboveMinThreshold &&
    327                 isBelowMaxThreshold;
    328     }
    329 
    330     public void calculateMinMaxVals() {
    331         prevMinX = calculatedMinX;
    332         prevMaxX = calculatedMaxX;
    333         prevMinY = calculatedMinY;
    334         prevMaxY = calculatedMaxY;
    335 
    336         calculatedMinX = userMinX;
    337         calculatedMaxX = userMaxX;
    338         calculatedMinY = userMinY;
    339         calculatedMaxY = userMaxY;
    340 
    341         // next we go through each series to update our min/max values:
    342         for (final XYSeries series : getSeriesSet()) {
    343             // step through each point in each series:
    344             for (int i = 0; i < series.size(); i++) {
    345                 Number thisX = series.getX(i);
    346                 Number thisY = series.getY(i);
    347                 if (isPointVisible(thisX, thisY)) {
    348                     // only calculate if a static value has not been set:
    349                     if (userMinX == null) {
    350                         if (thisX != null && (calculatedMinX == null ||
    351                                 thisX.doubleValue() < calculatedMinX.doubleValue())) {
    352                             calculatedMinX = thisX;
    353                         }
    354                     }
    355 
    356                     if (userMaxX == null) {
    357                         if (thisX != null && (calculatedMaxX == null ||
    358                                 thisX.doubleValue() > calculatedMaxX.doubleValue())) {
    359                             calculatedMaxX = thisX;
    360                         }
    361                     }
    362 
    363                     if (userMinY == null) {
    364                         if (thisY != null && (calculatedMinY == null ||
    365                                 thisY.doubleValue() < calculatedMinY.doubleValue())) {
    366                             calculatedMinY = thisY;
    367                         }
    368                     }
    369 
    370                     if (userMaxY == null) {
    371                         if (thisY != null && (calculatedMaxY == null || thisY.doubleValue() > calculatedMaxY.doubleValue())) {
    372                             calculatedMaxY = thisY;
    373                         }
    374                     }
    375                 }
    376             }
    377         }
    378 
    379         // at this point we now know what points are going to be visible on our
    380         // plot, but we still need to make corrections based on modes being used:
    381         // (grow, shrink etc.)
    382         switch (domainFramingModel) {
    383             case ORIGIN:
    384                 updateDomainMinMaxForOriginModel();
    385                 break;
    386             case EDGE:
    387                 updateDomainMinMaxForEdgeModel();
    388                 calculatedMinX = ApplyUserMinMax(calculatedMinX, domainLeftMin,
    389                         domainLeftMax);
    390                 calculatedMaxX = ApplyUserMinMax(calculatedMaxX,
    391                         domainRightMin, domainRightMax);
    392                 break;
    393             default:
    394                 throw new UnsupportedOperationException(
    395                         "Domain Framing Model not yet supported: " + domainFramingModel);
    396         }
    397 
    398         switch (rangeFramingModel) {
    399             case ORIGIN:
    400                 updateRangeMinMaxForOriginModel();
    401                 break;
    402             case EDGE:
    403             	if (getSeriesSet().size() > 0) {
    404 	                updateRangeMinMaxForEdgeModel();
    405 	                calculatedMinY = ApplyUserMinMax(calculatedMinY,
    406 	                        rangeBottomMin, rangeBottomMax);
    407 	                calculatedMaxY = ApplyUserMinMax(calculatedMaxY, rangeTopMin,
    408 	                        rangeTopMax);
    409             	}
    410                 break;
    411             default:
    412                 throw new UnsupportedOperationException(
    413                         "Range Framing Model not yet supported: " + domainFramingModel);
    414         }
    415 
    416         calculatedDomainOrigin = userDomainOrigin != null ? userDomainOrigin : getCalculatedMinX();
    417         calculatedRangeOrigin = this.userRangeOrigin != null ? userRangeOrigin : getCalculatedMinY();
    418     }
    419 
    420     /**
    421      * Should ONLY be called from updateMinMax.
    422      * Results are undefined otherwise.
    423      */
    424     private void updateDomainMinMaxForEdgeModel() {
    425         switch (domainUpperBoundaryMode) {
    426             case FIXED:
    427                 break;
    428             case AUTO:
    429                 break;
    430             case GROW:
    431                 if (!(prevMaxX == null || (calculatedMaxX.doubleValue() > prevMaxX.doubleValue()))) {
    432                     calculatedMaxX = prevMaxX;
    433                 }
    434                 break;
    435             case SHRINNK:
    436                 if (!(prevMaxX == null || calculatedMaxX.doubleValue() < prevMaxX.doubleValue())) {
    437                     calculatedMaxX = prevMaxX;
    438                 }
    439                 break;
    440             default:
    441                 throw new UnsupportedOperationException(
    442                         "DomainUpperBoundaryMode not yet implemented: " + domainUpperBoundaryMode);
    443         }
    444 
    445         switch (domainLowerBoundaryMode) {
    446             case FIXED:
    447                 break;
    448             case AUTO:
    449                 break;
    450             case GROW:
    451                 if (!(prevMinX == null || calculatedMinX.doubleValue() < prevMinX.doubleValue())) {
    452                     calculatedMinX = prevMinX;
    453                 }
    454                 break;
    455             case SHRINNK:
    456                 if (!(prevMinX == null || calculatedMinX.doubleValue() > prevMinX.doubleValue())) {
    457                     calculatedMinX = prevMinX;
    458                 }
    459                 break;
    460             default:
    461                 throw new UnsupportedOperationException(
    462                         "DomainLowerBoundaryMode not supported: " + domainLowerBoundaryMode);
    463         }
    464     }
    465 
    466     public void updateRangeMinMaxForEdgeModel() {
    467         switch (rangeUpperBoundaryMode) {
    468             case FIXED:
    469                 break;
    470             case AUTO:
    471                 break;
    472             case GROW:
    473                 if (!(prevMaxY == null || calculatedMaxY.doubleValue() > prevMaxY.doubleValue())) {
    474                     calculatedMaxY = prevMaxY;
    475                 }
    476                 break;
    477             case SHRINNK:
    478                 if (!(prevMaxY == null || calculatedMaxY.doubleValue() < prevMaxY.doubleValue())) {
    479                     calculatedMaxY = prevMaxY;
    480                 }
    481                 break;
    482             default:
    483                 throw new UnsupportedOperationException(
    484                         "RangeUpperBoundaryMode not supported: " + rangeUpperBoundaryMode);
    485         }
    486 
    487         switch (rangeLowerBoundaryMode) {
    488             case FIXED:
    489                 break;
    490             case AUTO:
    491                 break;
    492             case GROW:
    493                 if (!(prevMinY == null || calculatedMinY.doubleValue() < prevMinY.doubleValue())) {
    494                     calculatedMinY = prevMinY;
    495                 }
    496                 break;
    497             case SHRINNK:
    498                 if (!(prevMinY == null || calculatedMinY.doubleValue() > prevMinY.doubleValue())) {
    499                     calculatedMinY = prevMinY;
    500                 }
    501                 break;
    502             default:
    503                 throw new UnsupportedOperationException(
    504                         "RangeLowerBoundaryMode not supported: " + rangeLowerBoundaryMode);
    505         }
    506     }
    507 
    508     /**
    509      * Apply user supplied min and max to the calculated boundary value.
    510      *
    511      * @param value
    512      * @param min
    513      * @param max
    514      */
    515     private Number ApplyUserMinMax(Number value, Number min, Number max) {
    516         value = (((min == null) || (value.doubleValue() > min.doubleValue()))
    517                 ? value
    518                 : min);
    519         value = (((max == null) || (value.doubleValue() < max.doubleValue()))
    520                 ? value
    521                 : max);
    522         return value;
    523     }
    524 
    525     /**
    526      * Centers the domain axis on origin.
    527      *
    528      * @param origin
    529      */
    530     public void centerOnDomainOrigin(Number origin) {
    531         centerOnDomainOrigin(origin, null, BoundaryMode.AUTO);
    532     }
    533 
    534     /**
    535      * Centers the domain on origin, calculating the upper and lower boundaries of the axis
    536      * using mode and extent.
    537      *
    538      * @param origin
    539      * @param extent
    540      * @param mode
    541      */
    542     public void centerOnDomainOrigin(Number origin, Number extent, BoundaryMode mode) {
    543         if (origin == null) {
    544             throw new NullPointerException("Origin param cannot be null.");
    545         }
    546         domainFramingModel = XYFramingModel.ORIGIN;
    547         setUserDomainOrigin(origin);
    548         domainOriginExtent = extent;
    549         domainOriginBoundaryMode = mode;
    550 
    551         if (domainOriginBoundaryMode == BoundaryMode.FIXED) {
    552             double domO = userDomainOrigin.doubleValue();
    553             double domE = domainOriginExtent.doubleValue();
    554             userMaxX = domO + domE;
    555             userMinX = domO - domE;
    556         } else {
    557             userMaxX = null;
    558             userMinX = null;
    559         }
    560     }
    561 
    562     /**
    563      * Centers the range axis on origin.
    564      *
    565      * @param origin
    566      */
    567     public void centerOnRangeOrigin(Number origin) {
    568         centerOnRangeOrigin(origin, null, BoundaryMode.AUTO);
    569     }
    570 
    571     /**
    572      * Centers the domain on origin, calculating the upper and lower boundaries of the axis
    573      * using mode and extent.
    574      *
    575      * @param origin
    576      * @param extent
    577      * @param mode
    578      */
    579     @SuppressWarnings("SameParameterValue")
    580     public void centerOnRangeOrigin(Number origin, Number extent, BoundaryMode mode) {
    581         if (origin == null) {
    582             throw new NullPointerException("Origin param cannot be null.");
    583         }
    584         rangeFramingModel = XYFramingModel.ORIGIN;
    585         setUserRangeOrigin(origin);
    586         rangeOriginExtent = extent;
    587         rangeOriginBoundaryMode = mode;
    588 
    589         if (rangeOriginBoundaryMode == BoundaryMode.FIXED) {
    590             double raO = userRangeOrigin.doubleValue();
    591             double raE = rangeOriginExtent.doubleValue();
    592             userMaxY = raO + raE;
    593             userMinY = raO - raE;
    594         } else {
    595             userMaxY = null;
    596             userMinY = null;
    597         }
    598     }
    599 
    600     /**
    601      * Returns the distance between x and y.
    602      * Result is never a negative number.
    603      *
    604      * @param x
    605      * @param y
    606      * @return
    607      */
    608     private double distance(double x, double y) {
    609         if (x > y) {
    610             return x - y;
    611         } else {
    612             return y - x;
    613         }
    614     }
    615 
    616     public void updateDomainMinMaxForOriginModel() {
    617         double origin = userDomainOrigin.doubleValue();
    618         double maxXDelta = distance(calculatedMaxX.doubleValue(), origin);
    619         double minXDelta = distance(calculatedMinX.doubleValue(), origin);
    620         double delta = maxXDelta > minXDelta ? maxXDelta : minXDelta;
    621         double dlb = origin - delta;
    622         double dub = origin + delta;
    623         switch (domainOriginBoundaryMode) {
    624             case AUTO:
    625                 calculatedMinX = dlb;
    626                 calculatedMaxX = dub;
    627 
    628                 break;
    629             // if fixed, then the value already exists within "user" vals.
    630             case FIXED:
    631                 break;
    632             case GROW: {
    633 
    634                 if (prevMinX == null || dlb < prevMinX.doubleValue()) {
    635                     calculatedMinX = dlb;
    636                 } else {
    637                     calculatedMinX = prevMinX;
    638                 }
    639 
    640                 if (prevMaxX == null || dub > prevMaxX.doubleValue()) {
    641                     calculatedMaxX = dub;
    642                 } else {
    643                     calculatedMaxX = prevMaxX;
    644                 }
    645             }
    646             break;
    647             case SHRINNK:
    648                 if (prevMinX == null || dlb > prevMinX.doubleValue()) {
    649                     calculatedMinX = dlb;
    650                 } else {
    651                     calculatedMinX = prevMinX;
    652                 }
    653 
    654                 if (prevMaxX == null || dub < prevMaxX.doubleValue()) {
    655                     calculatedMaxX = dub;
    656                 } else {
    657                     calculatedMaxX = prevMaxX;
    658                 }
    659                 break;
    660             default:
    661                 throw new UnsupportedOperationException("Domain Origin Boundary Mode not yet supported: " + domainOriginBoundaryMode);
    662         }
    663     }
    664 
    665     public void updateRangeMinMaxForOriginModel() {
    666         switch (rangeOriginBoundaryMode) {
    667             case AUTO:
    668                 double origin = userRangeOrigin.doubleValue();
    669                 double maxYDelta = distance(calculatedMaxY.doubleValue(), origin);
    670                 double minYDelta = distance(calculatedMinY.doubleValue(), origin);
    671                 if (maxYDelta > minYDelta) {
    672                     calculatedMinY = origin - maxYDelta;
    673                     calculatedMaxY = origin + maxYDelta;
    674                 } else {
    675                     calculatedMinY = origin - minYDelta;
    676                     calculatedMaxY = origin + minYDelta;
    677                 }
    678                 break;
    679             case FIXED:
    680             case GROW:
    681             case SHRINNK:
    682             default:
    683                 throw new UnsupportedOperationException(
    684                         "Range Origin Boundary Mode not yet supported: " + rangeOriginBoundaryMode);
    685         }
    686     }
    687 
    688     /**
    689      * Convenience method - wraps XYGraphWidget.getTicksPerRangeLabel().
    690      * Equivalent to getGraphWidget().getTicksPerRangeLabel().
    691      *
    692      * @return
    693      */
    694     public int getTicksPerRangeLabel() {
    695         return graphWidget.getTicksPerRangeLabel();
    696     }
    697 
    698     /**
    699      * Convenience method - wraps XYGraphWidget.setTicksPerRangeLabel().
    700      * Equivalent to getGraphWidget().setTicksPerRangeLabel().
    701      *
    702      * @param ticksPerRangeLabel
    703      */
    704     public void setTicksPerRangeLabel(int ticksPerRangeLabel) {
    705         graphWidget.setTicksPerRangeLabel(ticksPerRangeLabel);
    706     }
    707 
    708     /**
    709      * Convenience method - wraps XYGraphWidget.getTicksPerDomainLabel().
    710      * Equivalent to getGraphWidget().getTicksPerDomainLabel().
    711      *
    712      * @return
    713      */
    714     public int getTicksPerDomainLabel() {
    715         return graphWidget.getTicksPerDomainLabel();
    716     }
    717 
    718     /**
    719      * Convenience method - wraps XYGraphWidget.setTicksPerDomainLabel().
    720      * Equivalent to getGraphWidget().setTicksPerDomainLabel().
    721      *
    722      * @param ticksPerDomainLabel
    723      */
    724     public void setTicksPerDomainLabel(int ticksPerDomainLabel) {
    725         graphWidget.setTicksPerDomainLabel(ticksPerDomainLabel);
    726     }
    727 
    728     public XYStepMode getDomainStepMode() {
    729         return domainStepMode;
    730     }
    731 
    732     public void setDomainStepMode(XYStepMode domainStepMode) {
    733         this.domainStepMode = domainStepMode;
    734     }
    735 
    736     public double getDomainStepValue() {
    737         return domainStepValue;
    738     }
    739 
    740     public void setDomainStepValue(double domainStepValue) {
    741         this.domainStepValue = domainStepValue;
    742     }
    743 
    744     public void setDomainStep(XYStepMode mode, double value) {
    745         setDomainStepMode(mode);
    746         setDomainStepValue(value);
    747     }
    748 
    749     public XYStepMode getRangeStepMode() {
    750         return rangeStepMode;
    751     }
    752 
    753     public void setRangeStepMode(XYStepMode rangeStepMode) {
    754         this.rangeStepMode = rangeStepMode;
    755     }
    756 
    757     public double getRangeStepValue() {
    758         return rangeStepValue;
    759     }
    760 
    761     public void setRangeStepValue(double rangeStepValue) {
    762         this.rangeStepValue = rangeStepValue;
    763     }
    764 
    765     public void setRangeStep(XYStepMode mode, double value) {
    766         setRangeStepMode(mode);
    767         setRangeStepValue(value);
    768     }
    769 
    770     public String getDomainLabel() {
    771         return getDomainLabelWidget().getText();
    772     }
    773 
    774     public void setDomainLabel(String domainLabel) {
    775         getDomainLabelWidget().setText(domainLabel);
    776     }
    777 
    778     public String getRangeLabel() {
    779         return getRangeLabelWidget().getText();
    780     }
    781 
    782     public void setRangeLabel(String rangeLabel) {
    783         getRangeLabelWidget().setText(rangeLabel);
    784     }
    785 
    786     public XYLegendWidget getLegendWidget() {
    787         return legendWidget;
    788     }
    789 
    790     public void setLegendWidget(XYLegendWidget legendWidget) {
    791         this.legendWidget = legendWidget;
    792     }
    793 
    794     public XYGraphWidget getGraphWidget() {
    795         return graphWidget;
    796     }
    797 
    798     public void setGraphWidget(XYGraphWidget graphWidget) {
    799         this.graphWidget = graphWidget;
    800     }
    801 
    802     public TextLabelWidget getDomainLabelWidget() {
    803         return domainLabelWidget;
    804     }
    805 
    806     public void setDomainLabelWidget(TextLabelWidget domainLabelWidget) {
    807         this.domainLabelWidget = domainLabelWidget;
    808     }
    809 
    810     public TextLabelWidget getRangeLabelWidget() {
    811         return rangeLabelWidget;
    812     }
    813 
    814     public void setRangeLabelWidget(TextLabelWidget rangeLabelWidget) {
    815         this.rangeLabelWidget = rangeLabelWidget;
    816     }
    817 
    818     /**
    819      * Convenience method - wraps XYGraphWidget.getRangeValueFormat().
    820      *
    821      * @return
    822      */
    823     public Format getRangeValueFormat() {
    824         return graphWidget.getRangeValueFormat();
    825     }
    826 
    827     /**
    828      * Convenience method - wraps XYGraphWidget.setRangeValueFormat().
    829      *
    830      * @param rangeValueFormat
    831      */
    832     public void setRangeValueFormat(Format rangeValueFormat) {
    833         graphWidget.setRangeValueFormat(rangeValueFormat);
    834     }
    835 
    836     /**
    837      * Convenience method - wraps XYGraphWidget.getDomainValueFormat().
    838      *
    839      * @return
    840      */
    841     public Format getDomainValueFormat() {
    842         return graphWidget.getDomainValueFormat();
    843     }
    844 
    845     /**
    846      * Convenience method - wraps XYGraphWidget.setDomainValueFormat().
    847      *
    848      * @param domainValueFormat
    849      */
    850     public void setDomainValueFormat(Format domainValueFormat) {
    851         graphWidget.setDomainValueFormat(domainValueFormat);
    852     }
    853 
    854     /**
    855      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    856      *
    857      * @param lowerBoundary
    858      * @param upperBoundary
    859      * @param mode
    860      */
    861     public synchronized void setDomainBoundaries(Number lowerBoundary, Number upperBoundary, BoundaryMode mode) {
    862         setDomainBoundaries(lowerBoundary, mode, upperBoundary, mode);
    863     }
    864 
    865     /**
    866      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    867      *
    868      * @param lowerBoundary
    869      * @param lowerBoundaryMode
    870      * @param upperBoundary
    871      * @param upperBoundaryMode
    872      */
    873     public synchronized void setDomainBoundaries(Number lowerBoundary, BoundaryMode lowerBoundaryMode,
    874                                                  Number upperBoundary, BoundaryMode upperBoundaryMode) {
    875         setDomainLowerBoundary(lowerBoundary, lowerBoundaryMode);
    876         setDomainUpperBoundary(upperBoundary, upperBoundaryMode);
    877     }
    878 
    879     /**
    880      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    881      *
    882      * @param lowerBoundary
    883      * @param upperBoundary
    884      * @param mode
    885      */
    886     public synchronized void setRangeBoundaries(Number lowerBoundary, Number upperBoundary, BoundaryMode mode) {
    887         setRangeBoundaries(lowerBoundary, mode, upperBoundary, mode);
    888     }
    889 
    890     /**
    891      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    892      *
    893      * @param lowerBoundary
    894      * @param lowerBoundaryMode
    895      * @param upperBoundary
    896      * @param upperBoundaryMode
    897      */
    898     public synchronized void setRangeBoundaries(Number lowerBoundary, BoundaryMode lowerBoundaryMode,
    899                                                 Number upperBoundary, BoundaryMode upperBoundaryMode) {
    900         setRangeLowerBoundary(lowerBoundary, lowerBoundaryMode);
    901         setRangeUpperBoundary(upperBoundary, upperBoundaryMode);
    902     }
    903 
    904     protected synchronized void setDomainUpperBoundaryMode(BoundaryMode mode) {
    905         this.domainUpperBoundaryMode = mode;
    906     }
    907 
    908     protected synchronized void setUserMaxX(Number boundary) {
    909         // Ifor 12/10/2011
    910         // you want null for auto grow and shrink
    911         //if(boundary == null) {
    912         //    throw new NullPointerException("Boundary value cannot be null.");
    913         //}
    914         this.userMaxX = boundary;
    915     }
    916 
    917     /**
    918      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    919      *
    920      * @param boundary
    921      * @param mode
    922      */
    923     public synchronized void setDomainUpperBoundary(Number boundary, BoundaryMode mode) {
    924         setUserMaxX((mode == BoundaryMode.FIXED) ? boundary : null);
    925         setDomainUpperBoundaryMode(mode);
    926         setDomainFramingModel(XYFramingModel.EDGE);
    927     }
    928 
    929     protected synchronized void setDomainLowerBoundaryMode(BoundaryMode mode) {
    930         this.domainLowerBoundaryMode = mode;
    931     }
    932 
    933     protected synchronized void setUserMinX(Number boundary) {
    934         // Ifor 12/10/2011
    935         // you want null for auto grow and shrink
    936         //if(boundary == null) {
    937         //    throw new NullPointerException("Boundary value cannot be null.");
    938         //}
    939         this.userMinX = boundary;
    940     }
    941 
    942     /**
    943      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    944      *
    945      * @param boundary
    946      * @param mode
    947      */
    948     public synchronized void setDomainLowerBoundary(Number boundary, BoundaryMode mode) {
    949         setUserMinX((mode == BoundaryMode.FIXED) ? boundary : null);
    950         setDomainLowerBoundaryMode(mode);
    951         setDomainFramingModel(XYFramingModel.EDGE);
    952         //updateMinMaxVals();
    953     }
    954 
    955     protected synchronized void setRangeUpperBoundaryMode(BoundaryMode mode) {
    956         this.rangeUpperBoundaryMode = mode;
    957     }
    958 
    959     protected synchronized void setUserMaxY(Number boundary) {
    960         // Ifor 12/10/2011
    961         // you want null for auto grow and shrink
    962         //if(boundary == null) {
    963         //    throw new NullPointerException("Boundary value cannot be null.");
    964         //}
    965         this.userMaxY = boundary;
    966     }
    967 
    968     /**
    969      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    970      *
    971      * @param boundary
    972      * @param mode
    973      */
    974     public synchronized void setRangeUpperBoundary(Number boundary, BoundaryMode mode) {
    975         setUserMaxY((mode == BoundaryMode.FIXED) ? boundary : null);
    976         setRangeUpperBoundaryMode(mode);
    977         setRangeFramingModel(XYFramingModel.EDGE);
    978     }
    979 
    980     protected synchronized void setRangeLowerBoundaryMode(BoundaryMode mode) {
    981         this.rangeLowerBoundaryMode = mode;
    982     }
    983 
    984     protected synchronized void setUserMinY(Number boundary) {
    985         // Ifor 12/10/2011
    986         // you want null for auto grow and shrink
    987         //if(boundary == null) {
    988         //    throw new NullPointerException("Boundary value cannot be null.");
    989         //}
    990         this.userMinY = boundary;
    991     }
    992 
    993     /**
    994      * Setup the boundary mode, boundary values only applicable in FIXED mode.
    995      *
    996      * @param boundary
    997      * @param mode
    998      */
    999     public synchronized void setRangeLowerBoundary(Number boundary, BoundaryMode mode) {
   1000         setUserMinY((mode == BoundaryMode.FIXED) ? boundary : null);
   1001         setRangeLowerBoundaryMode(mode);
   1002         setRangeFramingModel(XYFramingModel.EDGE);
   1003     }
   1004 
   1005     private Number getUserMinX() {
   1006         return userMinX;
   1007     }
   1008 
   1009     private Number getUserMaxX() {
   1010         return userMaxX;
   1011     }
   1012 
   1013     private Number getUserMinY() {
   1014         return userMinY;
   1015     }
   1016 
   1017     private Number getUserMaxY() {
   1018         return userMaxY;
   1019     }
   1020 
   1021     public Number getDomainOrigin() {
   1022         return calculatedDomainOrigin;
   1023     }
   1024 
   1025     public Number getRangeOrigin() {
   1026         return calculatedRangeOrigin;
   1027     }
   1028 
   1029     protected BoundaryMode getDomainUpperBoundaryMode() {
   1030         return domainUpperBoundaryMode;
   1031     }
   1032 
   1033     protected BoundaryMode getDomainLowerBoundaryMode() {
   1034         return domainLowerBoundaryMode;
   1035     }
   1036 
   1037     protected BoundaryMode getRangeUpperBoundaryMode() {
   1038         return rangeUpperBoundaryMode;
   1039     }
   1040 
   1041     protected BoundaryMode getRangeLowerBoundaryMode() {
   1042         return rangeLowerBoundaryMode;
   1043     }
   1044 
   1045     public synchronized void setUserDomainOrigin(Number origin) {
   1046         if (origin == null) {
   1047             throw new NullPointerException("Origin value cannot be null.");
   1048         }
   1049         this.userDomainOrigin = origin;
   1050     }
   1051 
   1052     public synchronized void setUserRangeOrigin(Number origin) {
   1053         if (origin == null) {
   1054             throw new NullPointerException("Origin value cannot be null.");
   1055         }
   1056         this.userRangeOrigin = origin;
   1057     }
   1058 
   1059     public XYFramingModel getDomainFramingModel() {
   1060         return domainFramingModel;
   1061     }
   1062 
   1063     @SuppressWarnings("SameParameterValue")
   1064     protected void setDomainFramingModel(XYFramingModel domainFramingModel) {
   1065         this.domainFramingModel = domainFramingModel;
   1066     }
   1067 
   1068     public XYFramingModel getRangeFramingModel() {
   1069 
   1070         return rangeFramingModel;
   1071     }
   1072 
   1073     @SuppressWarnings("SameParameterValue")
   1074     protected void setRangeFramingModel(XYFramingModel rangeFramingModel) {
   1075         this.rangeFramingModel = rangeFramingModel;
   1076     }
   1077 
   1078     /**
   1079      * CalculatedMinX value after the the framing model has been applied.
   1080      *
   1081      * @return
   1082      */
   1083     public Number getCalculatedMinX() {
   1084         return calculatedMinX != null ? calculatedMinX : getDefaultBounds().getMinX();
   1085     }
   1086 
   1087     /**
   1088      * CalculatedMaxX value after the the framing model has been applied.
   1089      *
   1090      * @return
   1091      */
   1092     public Number getCalculatedMaxX() {
   1093         return calculatedMaxX != null ? calculatedMaxX : getDefaultBounds().getMaxX();
   1094     }
   1095 
   1096     /**
   1097      * CalculatedMinY value after the the framing model has been applied.
   1098      *
   1099      * @return
   1100      */
   1101     public Number getCalculatedMinY() {
   1102         return calculatedMinY != null ? calculatedMinY : getDefaultBounds().getMinY();
   1103     }
   1104 
   1105     /**
   1106      * CalculatedMaxY value after the the framing model has been applied.
   1107      *
   1108      * @return
   1109      */
   1110     public Number getCalculatedMaxY() {
   1111         return calculatedMaxY != null ? calculatedMaxY : getDefaultBounds().getMaxY();
   1112     }
   1113 
   1114     public boolean isDrawDomainOriginEnabled() {
   1115         return drawDomainOriginEnabled;
   1116     }
   1117 
   1118     public void setDrawDomainOriginEnabled(boolean drawDomainOriginEnabled) {
   1119         this.drawDomainOriginEnabled = drawDomainOriginEnabled;
   1120     }
   1121 
   1122     public boolean isDrawRangeOriginEnabled() {
   1123         return drawRangeOriginEnabled;
   1124     }
   1125 
   1126     public void setDrawRangeOriginEnabled(boolean drawRangeOriginEnabled) {
   1127         this.drawRangeOriginEnabled = drawRangeOriginEnabled;
   1128     }
   1129 
   1130     /**
   1131      * Appends the specified marker to the end of plot's yValueMarkers list.
   1132      *
   1133      * @param marker The YValueMarker to be added.
   1134      * @return true if the object was successfully added, false otherwise.
   1135      */
   1136     public boolean addMarker(YValueMarker marker) {
   1137         if (yValueMarkers.contains(marker)) {
   1138             return false;
   1139         } else {
   1140             return yValueMarkers.add(marker);
   1141         }
   1142     }
   1143 
   1144     /**
   1145      * Removes the specified marker from the plot.
   1146      *
   1147      * @param marker
   1148      * @return The YValueMarker removed if successfull,  null otherwise.
   1149      */
   1150     public YValueMarker removeMarker(YValueMarker marker) {
   1151         int markerIndex = yValueMarkers.indexOf(marker);
   1152         if (markerIndex == -1) {
   1153             return null;
   1154         } else {
   1155             return yValueMarkers.remove(markerIndex);
   1156         }
   1157     }
   1158 
   1159     /**
   1160      * Convenience method - combines removeYMarkers() and removeXMarkers().
   1161      *
   1162      * @return
   1163      */
   1164     public int removeMarkers() {
   1165         int removed = removeXMarkers();
   1166         removed += removeYMarkers();
   1167         return removed;
   1168     }
   1169 
   1170     /**
   1171      * Removes all YValueMarker instances from the plot.
   1172      *
   1173      * @return
   1174      */
   1175     public int removeYMarkers() {
   1176         int numMarkersRemoved = yValueMarkers.size();
   1177         yValueMarkers.clear();
   1178         return numMarkersRemoved;
   1179     }
   1180 
   1181     /**
   1182      * Appends the specified marker to the end of plot's xValueMarkers list.
   1183      *
   1184      * @param marker The XValueMarker to be added.
   1185      * @return true if the object was successfully added, false otherwise.
   1186      */
   1187     public boolean addMarker(XValueMarker marker) {
   1188         return !xValueMarkers.contains(marker) && xValueMarkers.add(marker);
   1189     }
   1190 
   1191     /**
   1192      * Removes the specified marker from the plot.
   1193      *
   1194      * @param marker
   1195      * @return The XValueMarker removed if successfull,  null otherwise.
   1196      */
   1197     public XValueMarker removeMarker(XValueMarker marker) {
   1198         int markerIndex = xValueMarkers.indexOf(marker);
   1199         if (markerIndex == -1) {
   1200             return null;
   1201         } else {
   1202             return xValueMarkers.remove(markerIndex);
   1203         }
   1204     }
   1205 
   1206     /**
   1207      * Removes all XValueMarker instances from the plot.
   1208      *
   1209      * @return
   1210      */
   1211     public int removeXMarkers() {
   1212         int numMarkersRemoved = xValueMarkers.size();
   1213         xValueMarkers.clear();
   1214         return numMarkersRemoved;
   1215     }
   1216 
   1217     protected List<YValueMarker> getYValueMarkers() {
   1218         return yValueMarkers;
   1219     }
   1220 
   1221     protected List<XValueMarker> getXValueMarkers() {
   1222         return xValueMarkers;
   1223     }
   1224 
   1225     public RectRegion getDefaultBounds() {
   1226         return defaultBounds;
   1227     }
   1228 
   1229     public void setDefaultBounds(RectRegion defaultBounds) {
   1230         this.defaultBounds = defaultBounds;
   1231     }
   1232 
   1233     /**
   1234      * @return the rangeTopMin
   1235      */
   1236     public Number getRangeTopMin() {
   1237         return rangeTopMin;
   1238     }
   1239 
   1240     /**
   1241      * @param rangeTopMin the rangeTopMin to set
   1242      */
   1243     public synchronized void setRangeTopMin(Number rangeTopMin) {
   1244         this.rangeTopMin = rangeTopMin;
   1245     }
   1246 
   1247     /**
   1248      * @return the rangeTopMax
   1249      */
   1250     public Number getRangeTopMax() {
   1251         return rangeTopMax;
   1252     }
   1253 
   1254     /**
   1255      * @param rangeTopMax the rangeTopMax to set
   1256      */
   1257     public synchronized void setRangeTopMax(Number rangeTopMax) {
   1258         this.rangeTopMax = rangeTopMax;
   1259     }
   1260 
   1261     /**
   1262      * @return the rangeBottomMin
   1263      */
   1264     public Number getRangeBottomMin() {
   1265         return rangeBottomMin;
   1266     }
   1267 
   1268     /**
   1269      * @param rangeBottomMin the rangeBottomMin to set
   1270      */
   1271     public synchronized void setRangeBottomMin(Number rangeBottomMin) {
   1272         this.rangeBottomMin = rangeBottomMin;
   1273     }
   1274 
   1275     /**
   1276      * @return the rangeBottomMax
   1277      */
   1278     public Number getRangeBottomMax() {
   1279         return rangeBottomMax;
   1280     }
   1281 
   1282     /**
   1283      * @param rangeBottomMax the rangeBottomMax to set
   1284      */
   1285     public synchronized void setRangeBottomMax(Number rangeBottomMax) {
   1286         this.rangeBottomMax = rangeBottomMax;
   1287     }
   1288 
   1289     /**
   1290      * @return the domainLeftMin
   1291      */
   1292     public Number getDomainLeftMin() {
   1293         return domainLeftMin;
   1294     }
   1295 
   1296     /**
   1297      * @param domainLeftMin the domainLeftMin to set
   1298      */
   1299     public synchronized void setDomainLeftMin(Number domainLeftMin) {
   1300         this.domainLeftMin = domainLeftMin;
   1301     }
   1302 
   1303     /**
   1304      * @return the domainLeftMax
   1305      */
   1306     public Number getDomainLeftMax() {
   1307         return domainLeftMax;
   1308     }
   1309 
   1310     /**
   1311      * @param domainLeftMax the domainLeftMax to set
   1312      */
   1313     public synchronized void setDomainLeftMax(Number domainLeftMax) {
   1314         this.domainLeftMax = domainLeftMax;
   1315     }
   1316 
   1317     /**
   1318      * @return the domainRightMin
   1319      */
   1320     public Number getDomainRightMin() {
   1321         return domainRightMin;
   1322     }
   1323 
   1324     /**
   1325      * @param domainRightMin the domainRightMin to set
   1326      */
   1327     public synchronized void setDomainRightMin(Number domainRightMin) {
   1328         this.domainRightMin = domainRightMin;
   1329     }
   1330 
   1331     /**
   1332      * @return the domainRightMax
   1333      */
   1334     public Number getDomainRightMax() {
   1335         return domainRightMax;
   1336     }
   1337 
   1338     /**
   1339      * @param domainRightMax the domainRightMax to set
   1340      */
   1341     public synchronized void setDomainRightMax(Number domainRightMax) {
   1342         this.domainRightMax = domainRightMax;
   1343     }
   1344 }