/* * Copyright 2012 AndroidPlot.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.androidplot.xy; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.util.AttributeSet; import com.androidplot.Plot; import com.androidplot.R; import com.androidplot.ui.*; import com.androidplot.ui.TextOrientationType; import com.androidplot.ui.widget.TextLabelWidget; import com.androidplot.util.PixelUtils; import java.text.Format; import java.util.ArrayList; import java.util.List; /** * A View to graphically display x/y coordinates. */ public class XYPlot extends Plot<XYSeries, XYSeriesFormatter, XYSeriesRenderer> { private BoundaryMode domainOriginBoundaryMode; private BoundaryMode rangeOriginBoundaryMode; // widgets private XYLegendWidget legendWidget; private XYGraphWidget graphWidget; private TextLabelWidget domainLabelWidget; private TextLabelWidget rangeLabelWidget; private XYStepMode domainStepMode = XYStepMode.SUBDIVIDE; private double domainStepValue = 10; private XYStepMode rangeStepMode = XYStepMode.SUBDIVIDE; private double rangeStepValue = 10; // user settable min/max values private Number userMinX; private Number userMaxX; private Number userMinY; private Number userMaxY; // these are the final min/max used for dispplaying data private Number calculatedMinX; private Number calculatedMaxX; private Number calculatedMinY; private Number calculatedMaxY; // previous calculated min/max vals. // primarily used for GROW/SHRINK operations. private Number prevMinX; private Number prevMaxX; private Number prevMinY; private Number prevMaxY; // uses set boundary min and max values // should be null if not used. private Number rangeTopMin = null; private Number rangeTopMax = null; private Number rangeBottomMin = null; private Number rangeBottomMax = null; private Number domainLeftMin = null; private Number domainLeftMax = null; private Number domainRightMin = null; private Number domainRightMax = null; // used for calculating the domain/range extents that will be displayed on the plot. // using boundaries and origins are mutually exclusive. because of this, // setting one will disable the other. when only setting the FramingModel, // the origin or boundary is set to the current value of the plot. private XYFramingModel domainFramingModel = XYFramingModel.EDGE; private XYFramingModel rangeFramingModel = XYFramingModel.EDGE; private Number userDomainOrigin; private Number userRangeOrigin; private Number calculatedDomainOrigin; private Number calculatedRangeOrigin; @SuppressWarnings("FieldCanBeLocal") private Number domainOriginExtent = null; @SuppressWarnings("FieldCanBeLocal") private Number rangeOriginExtent = null; private BoundaryMode domainUpperBoundaryMode = BoundaryMode.AUTO; private BoundaryMode domainLowerBoundaryMode = BoundaryMode.AUTO; private BoundaryMode rangeUpperBoundaryMode = BoundaryMode.AUTO; private BoundaryMode rangeLowerBoundaryMode = BoundaryMode.AUTO; private boolean drawDomainOriginEnabled = true; private boolean drawRangeOriginEnabled = true; private ArrayList<YValueMarker> yValueMarkers; private ArrayList<XValueMarker> xValueMarkers; private RectRegion defaultBounds; private static final int DEFAULT_LEGEND_WIDGET_H_DP = 10; private static final int DEFAULT_LEGEND_WIDGET_ICON_SIZE_DP = 7; private static final int DEFAULT_GRAPH_WIDGET_H_DP = 18; private static final int DEFAULT_GRAPH_WIDGET_W_DP = 10; private static final int DEFAULT_DOMAIN_LABEL_WIDGET_H_DP = 10; private static final int DEFAULT_DOMAIN_LABEL_WIDGET_W_DP = 80; private static final int DEFAULT_RANGE_LABEL_WIDGET_H_DP = 50; private static final int DEFAULT_RANGE_LABEL_WIDGET_W_DP = 10; private static final int DEFAULT_LEGEND_WIDGET_Y_OFFSET_DP = 0; private static final int DEFAULT_LEGEND_WIDGET_X_OFFSET_DP = 40; private static final int DEFAULT_GRAPH_WIDGET_Y_OFFSET_DP = 0; private static final int DEFAULT_GRAPH_WIDGET_X_OFFSET_DP = 0; private static final int DEFAULT_DOMAIN_LABEL_WIDGET_Y_OFFSET_DP = 0; private static final int DEFAULT_DOMAIN_LABEL_WIDGET_X_OFFSET_DP = 20; private static final int DEFAULT_DOMAIN_LABEL_WIDGET_TEXT_SIZE_SP = 20; private static final int DEFAULT_RANGE_LABEL_WIDGET_Y_OFFSET_DP = 0; private static final int DEFAULT_RANGE_LABEL_WIDGET_X_OFFSET_DP = 0; private static final int DEFAULT_RANGE_LABEL_WIDGET_TEXT_SIZE_SP = 20; private static final int DEFAULT_GRAPH_WIDGET_TOP_MARGIN_DP = 3; private static final int DEFAULT_GRAPH_WIDGET_BOTTOM_MARGIN_DP = 3; private static final int DEFAULT_GRAPH_WIDGET_LEFT_MARGIN_DP = 3; private static final int DEFAULT_GRAPH_WIDGET_RIGHT_MARGIN_DP = 3; private static final int DEFAULT_PLOT_LEFT_MARGIN_DP = 2; private static final int DEFAULT_PLOT_RIGHT_MARGIN_DP = 2; private static final int DEFAULT_PLOT_BOTTOM_MARGIN_DP = 2; public XYPlot(Context context, String title) { super(context, title); } public XYPlot(Context context, String title, RenderMode mode) { super(context, title, mode); } public XYPlot(Context context, AttributeSet attributes) { super(context, attributes); } public XYPlot(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onPreInit() { legendWidget = new XYLegendWidget( getLayoutManager(), this, new SizeMetrics( PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_H_DP), SizeLayoutType.ABSOLUTE, 0.5f, SizeLayoutType.RELATIVE), new DynamicTableModel(0, 1), new SizeMetrics( PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_ICON_SIZE_DP), SizeLayoutType.ABSOLUTE, PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_ICON_SIZE_DP), SizeLayoutType.ABSOLUTE)); graphWidget = new XYGraphWidget( getLayoutManager(), this, new SizeMetrics( PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_H_DP), SizeLayoutType.FILL, PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_W_DP), SizeLayoutType.FILL)); Paint backgroundPaint = new Paint(); backgroundPaint.setColor(Color.DKGRAY); backgroundPaint.setStyle(Paint.Style.FILL); graphWidget.setBackgroundPaint(backgroundPaint); domainLabelWidget = new TextLabelWidget( getLayoutManager(), new SizeMetrics( PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_H_DP), SizeLayoutType.ABSOLUTE, PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_W_DP), SizeLayoutType.ABSOLUTE), TextOrientationType.HORIZONTAL); rangeLabelWidget = new TextLabelWidget( getLayoutManager(), new SizeMetrics( PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_H_DP), SizeLayoutType.ABSOLUTE, PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_W_DP), SizeLayoutType.ABSOLUTE), TextOrientationType.VERTICAL_ASCENDING); legendWidget.position( PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_X_OFFSET_DP), XLayoutStyle.ABSOLUTE_FROM_RIGHT, PixelUtils.dpToPix(DEFAULT_LEGEND_WIDGET_Y_OFFSET_DP), YLayoutStyle.ABSOLUTE_FROM_BOTTOM, AnchorPosition.RIGHT_BOTTOM); graphWidget.position( PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_X_OFFSET_DP), XLayoutStyle.ABSOLUTE_FROM_RIGHT, PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_Y_OFFSET_DP), YLayoutStyle.ABSOLUTE_FROM_CENTER, AnchorPosition.RIGHT_MIDDLE); domainLabelWidget.position( PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_X_OFFSET_DP), XLayoutStyle.ABSOLUTE_FROM_LEFT, PixelUtils.dpToPix(DEFAULT_DOMAIN_LABEL_WIDGET_Y_OFFSET_DP), YLayoutStyle.ABSOLUTE_FROM_BOTTOM, AnchorPosition.LEFT_BOTTOM); rangeLabelWidget.position( PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_X_OFFSET_DP), XLayoutStyle.ABSOLUTE_FROM_LEFT, PixelUtils.dpToPix(DEFAULT_RANGE_LABEL_WIDGET_Y_OFFSET_DP), YLayoutStyle.ABSOLUTE_FROM_CENTER, AnchorPosition.LEFT_MIDDLE); getLayoutManager().moveToTop(getTitleWidget()); getLayoutManager().moveToTop(getLegendWidget()); graphWidget.setMarginTop(PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_TOP_MARGIN_DP)); graphWidget.setMarginBottom(PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_BOTTOM_MARGIN_DP)); graphWidget.setMarginLeft(PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_LEFT_MARGIN_DP)); graphWidget.setMarginRight(PixelUtils.dpToPix(DEFAULT_GRAPH_WIDGET_RIGHT_MARGIN_DP)); getDomainLabelWidget().pack(); getRangeLabelWidget().pack(); setPlotMarginLeft(PixelUtils.dpToPix(DEFAULT_PLOT_LEFT_MARGIN_DP)); setPlotMarginRight(PixelUtils.dpToPix(DEFAULT_PLOT_RIGHT_MARGIN_DP)); setPlotMarginBottom(PixelUtils.dpToPix(DEFAULT_PLOT_BOTTOM_MARGIN_DP)); xValueMarkers = new ArrayList<XValueMarker>(); yValueMarkers = new ArrayList<YValueMarker>(); setDefaultBounds(new RectRegion(-1, 1, -1, 1)); } @Override protected void processAttrs(TypedArray attrs) { String domainLabelAttr = attrs.getString(R.styleable.xy_XYPlot_domainLabel); if(domainLabelAttr != null) { setDomainLabel(domainLabelAttr); } String rangeLabelAttr = attrs.getString(R.styleable.xy_XYPlot_rangeLabel); if(rangeLabelAttr != null) { setRangeLabel(rangeLabelAttr); } getDomainLabelWidget().getLabelPaint().setTextSize( attrs.getDimension(R.styleable.xy_XYPlot_domainLabelTextSize, getDomainLabelWidget().getLabelPaint().getTextSize())); getRangeLabelWidget().getLabelPaint().setTextSize( attrs.getDimension(R.styleable.xy_XYPlot_rangeLabelTextSize, getRangeLabelWidget().getLabelPaint().getTextSize())); getGraphWidget().setMarginTop(attrs.getDimension( R.styleable.xy_XYPlot_graphMarginTop, getGraphWidget().getMarginTop())); getGraphWidget().setMarginBottom(attrs.getDimension( R.styleable.xy_XYPlot_graphMarginBottom, getGraphWidget().getMarginBottom())); getGraphWidget().setMarginLeft(attrs.getDimension( R.styleable.xy_XYPlot_graphMarginLeft, getGraphWidget().getMarginLeft())); getGraphWidget().setMarginRight(attrs.getDimension( R.styleable.xy_XYPlot_graphMarginRight, getGraphWidget().getMarginRight())); } public void setGridPadding(float left, float top, float right, float bottom) { getGraphWidget().setGridPaddingTop(top); getGraphWidget().setGridPaddingBottom(bottom); getGraphWidget().setGridPaddingLeft(left); getGraphWidget().setGridPaddingRight(right); } @Override protected void notifyListenersBeforeDraw(Canvas canvas) { super.notifyListenersBeforeDraw(canvas); // this call must be AFTER the notify so that if the listener // is a synchronized series, it has the opportunity to // place a read lock on it's data. calculateMinMaxVals(); } /** * Checks whether the point is within the plot's graph area. * * @param x * @param y * @return */ public boolean containsPoint(float x, float y) { if (getGraphWidget().getGridRect() != null) { return getGraphWidget().getGridRect().contains(x, y); } return false; } /** * Convenience method - wraps containsPoint(PointF). * * @param point * @return */ public boolean containsPoint(PointF point) { return containsPoint(point.x, point.y); } public void setCursorPosition(PointF point) { getGraphWidget().setCursorPosition(point); } public void setCursorPosition(float x, float y) { getGraphWidget().setCursorPosition(x, y); } public Number getYVal(PointF point) { return getGraphWidget().getYVal(point); } public Number getXVal(PointF point) { return getGraphWidget().getXVal(point); } private boolean isXValWithinView(double xVal) { return (userMinY == null || xVal >= userMinY.doubleValue()) && userMaxY == null || xVal <= userMaxY.doubleValue(); } private boolean isPointVisible(Number x, Number y) { // values without both an x and y val arent visible if (x == null || y == null) { return false; } return isValWithinRange(y.doubleValue(), userMinY, userMaxY) && isValWithinRange(x.doubleValue(), userMinX, userMaxX); } private boolean isValWithinRange(double val, Number min, Number max) { boolean isAboveMinThreshold = min == null || val >= min.doubleValue(); boolean isBelowMaxThreshold = max == null || val <= max.doubleValue(); return isAboveMinThreshold && isBelowMaxThreshold; } public void calculateMinMaxVals() { prevMinX = calculatedMinX; prevMaxX = calculatedMaxX; prevMinY = calculatedMinY; prevMaxY = calculatedMaxY; calculatedMinX = userMinX; calculatedMaxX = userMaxX; calculatedMinY = userMinY; calculatedMaxY = userMaxY; // next we go through each series to update our min/max values: for (final XYSeries series : getSeriesSet()) { // step through each point in each series: for (int i = 0; i < series.size(); i++) { Number thisX = series.getX(i); Number thisY = series.getY(i); if (isPointVisible(thisX, thisY)) { // only calculate if a static value has not been set: if (userMinX == null) { if (thisX != null && (calculatedMinX == null || thisX.doubleValue() < calculatedMinX.doubleValue())) { calculatedMinX = thisX; } } if (userMaxX == null) { if (thisX != null && (calculatedMaxX == null || thisX.doubleValue() > calculatedMaxX.doubleValue())) { calculatedMaxX = thisX; } } if (userMinY == null) { if (thisY != null && (calculatedMinY == null || thisY.doubleValue() < calculatedMinY.doubleValue())) { calculatedMinY = thisY; } } if (userMaxY == null) { if (thisY != null && (calculatedMaxY == null || thisY.doubleValue() > calculatedMaxY.doubleValue())) { calculatedMaxY = thisY; } } } } } // at this point we now know what points are going to be visible on our // plot, but we still need to make corrections based on modes being used: // (grow, shrink etc.) switch (domainFramingModel) { case ORIGIN: updateDomainMinMaxForOriginModel(); break; case EDGE: updateDomainMinMaxForEdgeModel(); calculatedMinX = ApplyUserMinMax(calculatedMinX, domainLeftMin, domainLeftMax); calculatedMaxX = ApplyUserMinMax(calculatedMaxX, domainRightMin, domainRightMax); break; default: throw new UnsupportedOperationException( "Domain Framing Model not yet supported: " + domainFramingModel); } switch (rangeFramingModel) { case ORIGIN: updateRangeMinMaxForOriginModel(); break; case EDGE: if (getSeriesSet().size() > 0) { updateRangeMinMaxForEdgeModel(); calculatedMinY = ApplyUserMinMax(calculatedMinY, rangeBottomMin, rangeBottomMax); calculatedMaxY = ApplyUserMinMax(calculatedMaxY, rangeTopMin, rangeTopMax); } break; default: throw new UnsupportedOperationException( "Range Framing Model not yet supported: " + domainFramingModel); } calculatedDomainOrigin = userDomainOrigin != null ? userDomainOrigin : getCalculatedMinX(); calculatedRangeOrigin = this.userRangeOrigin != null ? userRangeOrigin : getCalculatedMinY(); } /** * Should ONLY be called from updateMinMax. * Results are undefined otherwise. */ private void updateDomainMinMaxForEdgeModel() { switch (domainUpperBoundaryMode) { case FIXED: break; case AUTO: break; case GROW: if (!(prevMaxX == null || (calculatedMaxX.doubleValue() > prevMaxX.doubleValue()))) { calculatedMaxX = prevMaxX; } break; case SHRINNK: if (!(prevMaxX == null || calculatedMaxX.doubleValue() < prevMaxX.doubleValue())) { calculatedMaxX = prevMaxX; } break; default: throw new UnsupportedOperationException( "DomainUpperBoundaryMode not yet implemented: " + domainUpperBoundaryMode); } switch (domainLowerBoundaryMode) { case FIXED: break; case AUTO: break; case GROW: if (!(prevMinX == null || calculatedMinX.doubleValue() < prevMinX.doubleValue())) { calculatedMinX = prevMinX; } break; case SHRINNK: if (!(prevMinX == null || calculatedMinX.doubleValue() > prevMinX.doubleValue())) { calculatedMinX = prevMinX; } break; default: throw new UnsupportedOperationException( "DomainLowerBoundaryMode not supported: " + domainLowerBoundaryMode); } } public void updateRangeMinMaxForEdgeModel() { switch (rangeUpperBoundaryMode) { case FIXED: break; case AUTO: break; case GROW: if (!(prevMaxY == null || calculatedMaxY.doubleValue() > prevMaxY.doubleValue())) { calculatedMaxY = prevMaxY; } break; case SHRINNK: if (!(prevMaxY == null || calculatedMaxY.doubleValue() < prevMaxY.doubleValue())) { calculatedMaxY = prevMaxY; } break; default: throw new UnsupportedOperationException( "RangeUpperBoundaryMode not supported: " + rangeUpperBoundaryMode); } switch (rangeLowerBoundaryMode) { case FIXED: break; case AUTO: break; case GROW: if (!(prevMinY == null || calculatedMinY.doubleValue() < prevMinY.doubleValue())) { calculatedMinY = prevMinY; } break; case SHRINNK: if (!(prevMinY == null || calculatedMinY.doubleValue() > prevMinY.doubleValue())) { calculatedMinY = prevMinY; } break; default: throw new UnsupportedOperationException( "RangeLowerBoundaryMode not supported: " + rangeLowerBoundaryMode); } } /** * Apply user supplied min and max to the calculated boundary value. * * @param value * @param min * @param max */ private Number ApplyUserMinMax(Number value, Number min, Number max) { value = (((min == null) || (value == null) || (value.doubleValue() > min.doubleValue())) ? value : min); value = (((max == null) || (value == null) || (value.doubleValue() < max.doubleValue())) ? value : max); return value; } /** * Centers the domain axis on origin. * * @param origin */ public void centerOnDomainOrigin(Number origin) { centerOnDomainOrigin(origin, null, BoundaryMode.AUTO); } /** * Centers the domain on origin, calculating the upper and lower boundaries of the axis * using mode and extent. * * @param origin * @param extent * @param mode */ public void centerOnDomainOrigin(Number origin, Number extent, BoundaryMode mode) { if (origin == null) { throw new NullPointerException("Origin param cannot be null."); } domainFramingModel = XYFramingModel.ORIGIN; setUserDomainOrigin(origin); domainOriginExtent = extent; domainOriginBoundaryMode = mode; if (domainOriginBoundaryMode == BoundaryMode.FIXED) { double domO = userDomainOrigin.doubleValue(); double domE = domainOriginExtent.doubleValue(); userMaxX = domO + domE; userMinX = domO - domE; } else { userMaxX = null; userMinX = null; } } /** * Centers the range axis on origin. * * @param origin */ public void centerOnRangeOrigin(Number origin) { centerOnRangeOrigin(origin, null, BoundaryMode.AUTO); } /** * Centers the domain on origin, calculating the upper and lower boundaries of the axis * using mode and extent. * * @param origin * @param extent * @param mode */ @SuppressWarnings("SameParameterValue") public void centerOnRangeOrigin(Number origin, Number extent, BoundaryMode mode) { if (origin == null) { throw new NullPointerException("Origin param cannot be null."); } rangeFramingModel = XYFramingModel.ORIGIN; setUserRangeOrigin(origin); rangeOriginExtent = extent; rangeOriginBoundaryMode = mode; if (rangeOriginBoundaryMode == BoundaryMode.FIXED) { double raO = userRangeOrigin.doubleValue(); double raE = rangeOriginExtent.doubleValue(); userMaxY = raO + raE; userMinY = raO - raE; } else { userMaxY = null; userMinY = null; } } /** * Returns the distance between x and y. * Result is never a negative number. * * @param x * @param y * @return */ private double distance(double x, double y) { if (x > y) { return x - y; } else { return y - x; } } public void updateDomainMinMaxForOriginModel() { double origin = userDomainOrigin.doubleValue(); double maxXDelta = distance(calculatedMaxX.doubleValue(), origin); double minXDelta = distance(calculatedMinX.doubleValue(), origin); double delta = maxXDelta > minXDelta ? maxXDelta : minXDelta; double dlb = origin - delta; double dub = origin + delta; switch (domainOriginBoundaryMode) { case AUTO: calculatedMinX = dlb; calculatedMaxX = dub; break; // if fixed, then the value already exists within "user" vals. case FIXED: break; case GROW: { if (prevMinX == null || dlb < prevMinX.doubleValue()) { calculatedMinX = dlb; } else { calculatedMinX = prevMinX; } if (prevMaxX == null || dub > prevMaxX.doubleValue()) { calculatedMaxX = dub; } else { calculatedMaxX = prevMaxX; } } break; case SHRINNK: if (prevMinX == null || dlb > prevMinX.doubleValue()) { calculatedMinX = dlb; } else { calculatedMinX = prevMinX; } if (prevMaxX == null || dub < prevMaxX.doubleValue()) { calculatedMaxX = dub; } else { calculatedMaxX = prevMaxX; } break; default: throw new UnsupportedOperationException("Domain Origin Boundary Mode not yet supported: " + domainOriginBoundaryMode); } } public void updateRangeMinMaxForOriginModel() { switch (rangeOriginBoundaryMode) { case AUTO: double origin = userRangeOrigin.doubleValue(); double maxYDelta = distance(calculatedMaxY.doubleValue(), origin); double minYDelta = distance(calculatedMinY.doubleValue(), origin); if (maxYDelta > minYDelta) { calculatedMinY = origin - maxYDelta; calculatedMaxY = origin + maxYDelta; } else { calculatedMinY = origin - minYDelta; calculatedMaxY = origin + minYDelta; } break; case FIXED: case GROW: case SHRINNK: default: throw new UnsupportedOperationException( "Range Origin Boundary Mode not yet supported: " + rangeOriginBoundaryMode); } } /** * Convenience method - wraps XYGraphWidget.getTicksPerRangeLabel(). * Equivalent to getGraphWidget().getTicksPerRangeLabel(). * * @return */ public int getTicksPerRangeLabel() { return graphWidget.getTicksPerRangeLabel(); } /** * Convenience method - wraps XYGraphWidget.setTicksPerRangeLabel(). * Equivalent to getGraphWidget().setTicksPerRangeLabel(). * * @param ticksPerRangeLabel */ public void setTicksPerRangeLabel(int ticksPerRangeLabel) { graphWidget.setTicksPerRangeLabel(ticksPerRangeLabel); } /** * Convenience method - wraps XYGraphWidget.getTicksPerDomainLabel(). * Equivalent to getGraphWidget().getTicksPerDomainLabel(). * * @return */ public int getTicksPerDomainLabel() { return graphWidget.getTicksPerDomainLabel(); } /** * Convenience method - wraps XYGraphWidget.setTicksPerDomainLabel(). * Equivalent to getGraphWidget().setTicksPerDomainLabel(). * * @param ticksPerDomainLabel */ public void setTicksPerDomainLabel(int ticksPerDomainLabel) { graphWidget.setTicksPerDomainLabel(ticksPerDomainLabel); } public XYStepMode getDomainStepMode() { return domainStepMode; } public void setDomainStepMode(XYStepMode domainStepMode) { this.domainStepMode = domainStepMode; } public double getDomainStepValue() { return domainStepValue; } public void setDomainStepValue(double domainStepValue) { this.domainStepValue = domainStepValue; } public void setDomainStep(XYStepMode mode, double value) { setDomainStepMode(mode); setDomainStepValue(value); } public XYStepMode getRangeStepMode() { return rangeStepMode; } public void setRangeStepMode(XYStepMode rangeStepMode) { this.rangeStepMode = rangeStepMode; } public double getRangeStepValue() { return rangeStepValue; } public void setRangeStepValue(double rangeStepValue) { this.rangeStepValue = rangeStepValue; } public void setRangeStep(XYStepMode mode, double value) { setRangeStepMode(mode); setRangeStepValue(value); } public String getDomainLabel() { return getDomainLabelWidget().getText(); } public void setDomainLabel(String domainLabel) { getDomainLabelWidget().setText(domainLabel); } public String getRangeLabel() { return getRangeLabelWidget().getText(); } public void setRangeLabel(String rangeLabel) { getRangeLabelWidget().setText(rangeLabel); } public XYLegendWidget getLegendWidget() { return legendWidget; } public void setLegendWidget(XYLegendWidget legendWidget) { this.legendWidget = legendWidget; } public XYGraphWidget getGraphWidget() { return graphWidget; } public void setGraphWidget(XYGraphWidget graphWidget) { this.graphWidget = graphWidget; } public TextLabelWidget getDomainLabelWidget() { return domainLabelWidget; } public void setDomainLabelWidget(TextLabelWidget domainLabelWidget) { this.domainLabelWidget = domainLabelWidget; } public TextLabelWidget getRangeLabelWidget() { return rangeLabelWidget; } public void setRangeLabelWidget(TextLabelWidget rangeLabelWidget) { this.rangeLabelWidget = rangeLabelWidget; } /** * Convenience method - wraps XYGraphWidget.getRangeValueFormat(). * * @return */ public Format getRangeValueFormat() { return graphWidget.getRangeValueFormat(); } /** * Convenience method - wraps XYGraphWidget.setRangeValueFormat(). * * @param rangeValueFormat */ public void setRangeValueFormat(Format rangeValueFormat) { graphWidget.setRangeValueFormat(rangeValueFormat); } /** * Convenience method - wraps XYGraphWidget.getDomainValueFormat(). * * @return */ public Format getDomainValueFormat() { return graphWidget.getDomainValueFormat(); } /** * Convenience method - wraps XYGraphWidget.setDomainValueFormat(). * * @param domainValueFormat */ public void setDomainValueFormat(Format domainValueFormat) { graphWidget.setDomainValueFormat(domainValueFormat); } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param lowerBoundary * @param upperBoundary * @param mode */ public synchronized void setDomainBoundaries(Number lowerBoundary, Number upperBoundary, BoundaryMode mode) { setDomainBoundaries(lowerBoundary, mode, upperBoundary, mode); } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param lowerBoundary * @param lowerBoundaryMode * @param upperBoundary * @param upperBoundaryMode */ public synchronized void setDomainBoundaries(Number lowerBoundary, BoundaryMode lowerBoundaryMode, Number upperBoundary, BoundaryMode upperBoundaryMode) { setDomainLowerBoundary(lowerBoundary, lowerBoundaryMode); setDomainUpperBoundary(upperBoundary, upperBoundaryMode); } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param lowerBoundary * @param upperBoundary * @param mode */ public synchronized void setRangeBoundaries(Number lowerBoundary, Number upperBoundary, BoundaryMode mode) { setRangeBoundaries(lowerBoundary, mode, upperBoundary, mode); } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param lowerBoundary * @param lowerBoundaryMode * @param upperBoundary * @param upperBoundaryMode */ public synchronized void setRangeBoundaries(Number lowerBoundary, BoundaryMode lowerBoundaryMode, Number upperBoundary, BoundaryMode upperBoundaryMode) { setRangeLowerBoundary(lowerBoundary, lowerBoundaryMode); setRangeUpperBoundary(upperBoundary, upperBoundaryMode); } protected synchronized void setDomainUpperBoundaryMode(BoundaryMode mode) { this.domainUpperBoundaryMode = mode; } protected synchronized void setUserMaxX(Number boundary) { // Ifor 12/10/2011 // you want null for auto grow and shrink //if(boundary == null) { // throw new NullPointerException("Boundary value cannot be null."); //} this.userMaxX = boundary; } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param boundary * @param mode */ public synchronized void setDomainUpperBoundary(Number boundary, BoundaryMode mode) { setUserMaxX((mode == BoundaryMode.FIXED) ? boundary : null); setDomainUpperBoundaryMode(mode); setDomainFramingModel(XYFramingModel.EDGE); } protected synchronized void setDomainLowerBoundaryMode(BoundaryMode mode) { this.domainLowerBoundaryMode = mode; } protected synchronized void setUserMinX(Number boundary) { // Ifor 12/10/2011 // you want null for auto grow and shrink //if(boundary == null) { // throw new NullPointerException("Boundary value cannot be null."); //} this.userMinX = boundary; } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param boundary * @param mode */ public synchronized void setDomainLowerBoundary(Number boundary, BoundaryMode mode) { setUserMinX((mode == BoundaryMode.FIXED) ? boundary : null); setDomainLowerBoundaryMode(mode); setDomainFramingModel(XYFramingModel.EDGE); //updateMinMaxVals(); } protected synchronized void setRangeUpperBoundaryMode(BoundaryMode mode) { this.rangeUpperBoundaryMode = mode; } protected synchronized void setUserMaxY(Number boundary) { // Ifor 12/10/2011 // you want null for auto grow and shrink //if(boundary == null) { // throw new NullPointerException("Boundary value cannot be null."); //} this.userMaxY = boundary; } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param boundary * @param mode */ public synchronized void setRangeUpperBoundary(Number boundary, BoundaryMode mode) { setUserMaxY((mode == BoundaryMode.FIXED) ? boundary : null); setRangeUpperBoundaryMode(mode); setRangeFramingModel(XYFramingModel.EDGE); } protected synchronized void setRangeLowerBoundaryMode(BoundaryMode mode) { this.rangeLowerBoundaryMode = mode; } protected synchronized void setUserMinY(Number boundary) { // Ifor 12/10/2011 // you want null for auto grow and shrink //if(boundary == null) { // throw new NullPointerException("Boundary value cannot be null."); //} this.userMinY = boundary; } /** * Setup the boundary mode, boundary values only applicable in FIXED mode. * * @param boundary * @param mode */ public synchronized void setRangeLowerBoundary(Number boundary, BoundaryMode mode) { setUserMinY((mode == BoundaryMode.FIXED) ? boundary : null); setRangeLowerBoundaryMode(mode); setRangeFramingModel(XYFramingModel.EDGE); } private Number getUserMinX() { return userMinX; } private Number getUserMaxX() { return userMaxX; } private Number getUserMinY() { return userMinY; } private Number getUserMaxY() { return userMaxY; } public Number getDomainOrigin() { return calculatedDomainOrigin; } public Number getRangeOrigin() { return calculatedRangeOrigin; } protected BoundaryMode getDomainUpperBoundaryMode() { return domainUpperBoundaryMode; } protected BoundaryMode getDomainLowerBoundaryMode() { return domainLowerBoundaryMode; } protected BoundaryMode getRangeUpperBoundaryMode() { return rangeUpperBoundaryMode; } protected BoundaryMode getRangeLowerBoundaryMode() { return rangeLowerBoundaryMode; } public synchronized void setUserDomainOrigin(Number origin) { if (origin == null) { throw new NullPointerException("Origin value cannot be null."); } this.userDomainOrigin = origin; } public synchronized void setUserRangeOrigin(Number origin) { if (origin == null) { throw new NullPointerException("Origin value cannot be null."); } this.userRangeOrigin = origin; } public XYFramingModel getDomainFramingModel() { return domainFramingModel; } @SuppressWarnings("SameParameterValue") protected void setDomainFramingModel(XYFramingModel domainFramingModel) { this.domainFramingModel = domainFramingModel; } public XYFramingModel getRangeFramingModel() { return rangeFramingModel; } @SuppressWarnings("SameParameterValue") protected void setRangeFramingModel(XYFramingModel rangeFramingModel) { this.rangeFramingModel = rangeFramingModel; } /** * CalculatedMinX value after the the framing model has been applied. * * @return */ public Number getCalculatedMinX() { return calculatedMinX != null ? calculatedMinX : getDefaultBounds().getMinX(); } /** * CalculatedMaxX value after the the framing model has been applied. * * @return */ public Number getCalculatedMaxX() { return calculatedMaxX != null ? calculatedMaxX : getDefaultBounds().getMaxX(); } /** * CalculatedMinY value after the the framing model has been applied. * * @return */ public Number getCalculatedMinY() { return calculatedMinY != null ? calculatedMinY : getDefaultBounds().getMinY(); } /** * CalculatedMaxY value after the the framing model has been applied. * * @return */ public Number getCalculatedMaxY() { return calculatedMaxY != null ? calculatedMaxY : getDefaultBounds().getMaxY(); } public boolean isDrawDomainOriginEnabled() { return drawDomainOriginEnabled; } public void setDrawDomainOriginEnabled(boolean drawDomainOriginEnabled) { this.drawDomainOriginEnabled = drawDomainOriginEnabled; } public boolean isDrawRangeOriginEnabled() { return drawRangeOriginEnabled; } public void setDrawRangeOriginEnabled(boolean drawRangeOriginEnabled) { this.drawRangeOriginEnabled = drawRangeOriginEnabled; } /** * Appends the specified marker to the end of plot's yValueMarkers list. * * @param marker The YValueMarker to be added. * @return true if the object was successfully added, false otherwise. */ public boolean addMarker(YValueMarker marker) { if (yValueMarkers.contains(marker)) { return false; } else { return yValueMarkers.add(marker); } } /** * Removes the specified marker from the plot. * * @param marker * @return The YValueMarker removed if successfull, null otherwise. */ public YValueMarker removeMarker(YValueMarker marker) { int markerIndex = yValueMarkers.indexOf(marker); if (markerIndex == -1) { return null; } else { return yValueMarkers.remove(markerIndex); } } /** * Convenience method - combines removeYMarkers() and removeXMarkers(). * * @return */ public int removeMarkers() { int removed = removeXMarkers(); removed += removeYMarkers(); return removed; } /** * Removes all YValueMarker instances from the plot. * * @return */ public int removeYMarkers() { int numMarkersRemoved = yValueMarkers.size(); yValueMarkers.clear(); return numMarkersRemoved; } /** * Appends the specified marker to the end of plot's xValueMarkers list. * * @param marker The XValueMarker to be added. * @return true if the object was successfully added, false otherwise. */ public boolean addMarker(XValueMarker marker) { return !xValueMarkers.contains(marker) && xValueMarkers.add(marker); } /** * Removes the specified marker from the plot. * * @param marker * @return The XValueMarker removed if successfull, null otherwise. */ public XValueMarker removeMarker(XValueMarker marker) { int markerIndex = xValueMarkers.indexOf(marker); if (markerIndex == -1) { return null; } else { return xValueMarkers.remove(markerIndex); } } /** * Removes all XValueMarker instances from the plot. * * @return */ public int removeXMarkers() { int numMarkersRemoved = xValueMarkers.size(); xValueMarkers.clear(); return numMarkersRemoved; } protected List<YValueMarker> getYValueMarkers() { return yValueMarkers; } protected List<XValueMarker> getXValueMarkers() { return xValueMarkers; } public RectRegion getDefaultBounds() { return defaultBounds; } public void setDefaultBounds(RectRegion defaultBounds) { this.defaultBounds = defaultBounds; } /** * @return the rangeTopMin */ public Number getRangeTopMin() { return rangeTopMin; } /** * @param rangeTopMin the rangeTopMin to set */ public synchronized void setRangeTopMin(Number rangeTopMin) { this.rangeTopMin = rangeTopMin; } /** * @return the rangeTopMax */ public Number getRangeTopMax() { return rangeTopMax; } /** * @param rangeTopMax the rangeTopMax to set */ public synchronized void setRangeTopMax(Number rangeTopMax) { this.rangeTopMax = rangeTopMax; } /** * @return the rangeBottomMin */ public Number getRangeBottomMin() { return rangeBottomMin; } /** * @param rangeBottomMin the rangeBottomMin to set */ public synchronized void setRangeBottomMin(Number rangeBottomMin) { this.rangeBottomMin = rangeBottomMin; } /** * @return the rangeBottomMax */ public Number getRangeBottomMax() { return rangeBottomMax; } /** * @param rangeBottomMax the rangeBottomMax to set */ public synchronized void setRangeBottomMax(Number rangeBottomMax) { this.rangeBottomMax = rangeBottomMax; } /** * @return the domainLeftMin */ public Number getDomainLeftMin() { return domainLeftMin; } /** * @param domainLeftMin the domainLeftMin to set */ public synchronized void setDomainLeftMin(Number domainLeftMin) { this.domainLeftMin = domainLeftMin; } /** * @return the domainLeftMax */ public Number getDomainLeftMax() { return domainLeftMax; } /** * @param domainLeftMax the domainLeftMax to set */ public synchronized void setDomainLeftMax(Number domainLeftMax) { this.domainLeftMax = domainLeftMax; } /** * @return the domainRightMin */ public Number getDomainRightMin() { return domainRightMin; } /** * @param domainRightMin the domainRightMin to set */ public synchronized void setDomainRightMin(Number domainRightMin) { this.domainRightMin = domainRightMin; } /** * @return the domainRightMax */ public Number getDomainRightMax() { return domainRightMax; } /** * @param domainRightMax the domainRightMax to set */ public synchronized void setDomainRightMax(Number domainRightMax) { this.domainRightMax = domainRightMax; } }