| |
| package com.github.mikephil.charting.renderer; |
| |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.Paint; |
| import android.graphics.Paint.Style; |
| |
| import com.github.mikephil.charting.components.AxisBase; |
| import com.github.mikephil.charting.utils.MPPointD; |
| import com.github.mikephil.charting.utils.Transformer; |
| import com.github.mikephil.charting.utils.Utils; |
| import com.github.mikephil.charting.utils.ViewPortHandler; |
| |
| /** |
| * Baseclass of all axis renderers. |
| * |
| * @author Philipp Jahoda |
| */ |
| public abstract class AxisRenderer extends Renderer { |
| |
| /** base axis this axis renderer works with */ |
| protected AxisBase mAxis; |
| |
| /** transformer to transform values to screen pixels and return */ |
| protected Transformer mTrans; |
| |
| /** |
| * paint object for the grid lines |
| */ |
| protected Paint mGridPaint; |
| |
| /** |
| * paint for the x-label values |
| */ |
| protected Paint mAxisLabelPaint; |
| |
| /** |
| * paint for the line surrounding the chart |
| */ |
| protected Paint mAxisLinePaint; |
| |
| /** |
| * paint used for the limit lines |
| */ |
| protected Paint mLimitLinePaint; |
| |
| public AxisRenderer(ViewPortHandler viewPortHandler, Transformer trans, AxisBase axis) { |
| super(viewPortHandler); |
| |
| this.mTrans = trans; |
| this.mAxis = axis; |
| |
| if(mViewPortHandler != null) { |
| |
| mAxisLabelPaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
| |
| mGridPaint = new Paint(); |
| mGridPaint.setColor(Color.GRAY); |
| mGridPaint.setStrokeWidth(1f); |
| mGridPaint.setStyle(Style.STROKE); |
| mGridPaint.setAlpha(90); |
| |
| mAxisLinePaint = new Paint(); |
| mAxisLinePaint.setColor(Color.BLACK); |
| mAxisLinePaint.setStrokeWidth(1f); |
| mAxisLinePaint.setStyle(Style.STROKE); |
| |
| mLimitLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
| mLimitLinePaint.setStyle(Paint.Style.STROKE); |
| } |
| } |
| |
| /** |
| * Returns the Paint object used for drawing the axis (labels). |
| * |
| * @return |
| */ |
| public Paint getPaintAxisLabels() { |
| return mAxisLabelPaint; |
| } |
| |
| /** |
| * Returns the Paint object that is used for drawing the grid-lines of the |
| * axis. |
| * |
| * @return |
| */ |
| public Paint getPaintGrid() { |
| return mGridPaint; |
| } |
| |
| /** |
| * Returns the Paint object that is used for drawing the axis-line that goes |
| * alongside the axis. |
| * |
| * @return |
| */ |
| public Paint getPaintAxisLine() { |
| return mAxisLinePaint; |
| } |
| |
| /** |
| * Returns the Transformer object used for transforming the axis values. |
| * |
| * @return |
| */ |
| public Transformer getTransformer() { |
| return mTrans; |
| } |
| |
| /** |
| * Computes the axis values. |
| * |
| * @param min - the minimum value in the data object for this axis |
| * @param max - the maximum value in the data object for this axis |
| */ |
| public void computeAxis(float min, float max, boolean inverted) { |
| |
| // calculate the starting and entry point of the y-labels (depending on |
| // zoom / contentrect bounds) |
| if (mViewPortHandler != null && mViewPortHandler.contentWidth() > 10 && !mViewPortHandler.isFullyZoomedOutY()) { |
| |
| MPPointD p1 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop()); |
| MPPointD p2 = mTrans.getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom()); |
| |
| if (!inverted) { |
| |
| min = (float) p2.y; |
| max = (float) p1.y; |
| } else { |
| |
| min = (float) p1.y; |
| max = (float) p2.y; |
| } |
| |
| MPPointD.recycleInstance(p1); |
| MPPointD.recycleInstance(p2); |
| } |
| |
| computeAxisValues(min, max); |
| } |
| |
| /** |
| * Sets up the axis values. Computes the desired number of labels between the two given extremes. |
| * |
| * @return |
| */ |
| protected void computeAxisValues(float min, float max) { |
| |
| float yMin = min; |
| float yMax = max; |
| |
| int labelCount = mAxis.getLabelCount(); |
| double range = Math.abs(yMax - yMin); |
| |
| if (labelCount == 0 || range <= 0) { |
| mAxis.mEntries = new float[]{}; |
| mAxis.mEntryCount = 0; |
| return; |
| } |
| |
| // Find out how much spacing (in y value space) between axis values |
| double rawInterval = range / labelCount; |
| if (Double.isInfinite(rawInterval)) |
| { |
| rawInterval = range > 0.0 && !Double.isInfinite(range) ? range : 1.0; |
| } |
| double interval = Utils.roundToNextSignificant(rawInterval); |
| |
| // If granularity is enabled, then do not allow the interval to go below specified granularity. |
| // This is used to avoid repeated values when rounding values for display. |
| if (mAxis.isGranularityEnabled()) |
| interval = interval < mAxis.getGranularity() ? mAxis.getGranularity() : interval; |
| |
| // Normalize interval |
| double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval))); |
| int intervalSigDigit = (int) (interval / intervalMagnitude); |
| if (intervalSigDigit > 5) { |
| // Use one order of magnitude higher, to avoid intervals like 0.9 or |
| // 90 |
| interval = Math.floor(10 * intervalMagnitude); |
| } |
| |
| boolean centeringEnabled = mAxis.isCenterAxisLabelsEnabled(); |
| int n = centeringEnabled ? 1 : 0; |
| |
| // force label count |
| if (mAxis.isForceLabelsEnabled()) { |
| |
| float step = (float) range / (float) (labelCount - 1); |
| mAxis.mEntryCount = labelCount; |
| |
| if (mAxis.mEntries.length < labelCount) { |
| // Ensure stops contains at least numStops elements. |
| mAxis.mEntries = new float[labelCount]; |
| } |
| |
| float v = min; |
| |
| for (int i = 0; i < labelCount; i++) { |
| mAxis.mEntries[i] = v; |
| v += step; |
| } |
| |
| n = labelCount; |
| |
| // no forced count |
| } else { |
| |
| double first = interval == 0.0 ? 0.0 : Math.ceil(yMin / interval) * interval; |
| if(centeringEnabled) { |
| first -= interval; |
| } |
| |
| double last = interval == 0.0 ? 0.0 : Utils.nextUp(Math.floor(yMax / interval) * interval); |
| |
| double f; |
| int i; |
| |
| if (interval != 0.0) { |
| for (f = first; f <= last; f += interval) { |
| ++n; |
| } |
| } |
| |
| mAxis.mEntryCount = n; |
| |
| if (mAxis.mEntries.length < n) { |
| // Ensure stops contains at least numStops elements. |
| mAxis.mEntries = new float[n]; |
| } |
| |
| for (f = first, i = 0; i < n; f += interval, ++i) { |
| |
| if (f == 0.0) // Fix for negative zero case (Where value == -0.0, and 0.0 == -0.0) |
| f = 0.0; |
| |
| mAxis.mEntries[i] = (float) f; |
| } |
| } |
| |
| // set decimals |
| if (interval < 1) { |
| mAxis.mDecimals = (int) Math.ceil(-Math.log10(interval)); |
| } else { |
| mAxis.mDecimals = 0; |
| } |
| |
| if (centeringEnabled) { |
| |
| if (mAxis.mCenteredEntries.length < n) { |
| mAxis.mCenteredEntries = new float[n]; |
| } |
| |
| float offset = (mAxis.mEntries[1] - mAxis.mEntries[0]) / 2f; |
| |
| for (int i = 0; i < n; i++) { |
| mAxis.mCenteredEntries[i] = mAxis.mEntries[i] + offset; |
| } |
| } |
| } |
| |
| /** |
| * Draws the axis labels to the screen. |
| * |
| * @param c |
| */ |
| public abstract void renderAxisLabels(Canvas c); |
| |
| /** |
| * Draws the grid lines belonging to the axis. |
| * |
| * @param c |
| */ |
| public abstract void renderGridLines(Canvas c); |
| |
| /** |
| * Draws the line that goes alongside the axis. |
| * |
| * @param c |
| */ |
| public abstract void renderAxisLine(Canvas c); |
| |
| /** |
| * Draws the LimitLines associated with this axis to the screen. |
| * |
| * @param c |
| */ |
| public abstract void renderLimitLines(Canvas c); |
| } |