summaryrefslogtreecommitdiff
path: root/AndroidPlot-Core/src/main/java/com/androidplot/xy/XYPlot.java
diff options
context:
space:
mode:
Diffstat (limited to 'AndroidPlot-Core/src/main/java/com/androidplot/xy/XYPlot.java')
-rw-r--r--AndroidPlot-Core/src/main/java/com/androidplot/xy/XYPlot.java1344
1 files changed, 1344 insertions, 0 deletions
diff --git a/AndroidPlot-Core/src/main/java/com/androidplot/xy/XYPlot.java b/AndroidPlot-Core/src/main/java/com/androidplot/xy/XYPlot.java
new file mode 100644
index 0000000..d3c286c
--- /dev/null
+++ b/AndroidPlot-Core/src/main/java/com/androidplot/xy/XYPlot.java
@@ -0,0 +1,1344 @@
+/*
+ * 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.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.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_RANGE_LABEL_WIDGET_Y_OFFSET_DP = 0;
+ private static final int DEFAULT_RANGE_LABEL_WIDGET_X_OFFSET_DP = 0;
+
+ private static final int DEFAULT_GRAPH_WIDGET_TOP_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.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));
+ }
+
+
+ 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.doubleValue() > min.doubleValue()))
+ ? value
+ : min);
+ value = (((max == 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;
+ }
+} \ No newline at end of file