| |
| package com.github.mikephil.charting.charts; |
| |
| import android.annotation.SuppressLint; |
| import android.annotation.TargetApi; |
| import android.content.Context; |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.Matrix; |
| import android.graphics.Paint; |
| import android.graphics.Paint.Style; |
| import android.graphics.RectF; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.view.MotionEvent; |
| |
| import com.github.mikephil.charting.components.XAxis.XAxisPosition; |
| import com.github.mikephil.charting.components.YAxis; |
| import com.github.mikephil.charting.components.YAxis.AxisDependency; |
| import com.github.mikephil.charting.data.BarLineScatterCandleBubbleData; |
| import com.github.mikephil.charting.data.Entry; |
| import com.github.mikephil.charting.highlight.ChartHighlighter; |
| import com.github.mikephil.charting.highlight.Highlight; |
| import com.github.mikephil.charting.interfaces.dataprovider.BarLineScatterCandleBubbleDataProvider; |
| import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet; |
| import com.github.mikephil.charting.jobs.AnimatedMoveViewJob; |
| import com.github.mikephil.charting.jobs.AnimatedZoomJob; |
| import com.github.mikephil.charting.jobs.MoveViewJob; |
| import com.github.mikephil.charting.jobs.ZoomJob; |
| import com.github.mikephil.charting.listener.BarLineChartTouchListener; |
| import com.github.mikephil.charting.listener.OnDrawListener; |
| import com.github.mikephil.charting.renderer.XAxisRenderer; |
| import com.github.mikephil.charting.renderer.YAxisRenderer; |
| import com.github.mikephil.charting.utils.MPPointD; |
| import com.github.mikephil.charting.utils.MPPointF; |
| import com.github.mikephil.charting.utils.Transformer; |
| import com.github.mikephil.charting.utils.Utils; |
| |
| /** |
| * Base-class of LineChart, BarChart, ScatterChart and CandleStickChart. |
| * |
| * @author Philipp Jahoda |
| */ |
| @SuppressLint("RtlHardcoded") |
| public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<? extends |
| IBarLineScatterCandleBubbleDataSet<? extends Entry>>> |
| extends Chart<T> implements BarLineScatterCandleBubbleDataProvider { |
| |
| /** |
| * the maximum number of entries to which values will be drawn |
| * (entry numbers greater than this value will cause value-labels to disappear) |
| */ |
| protected int mMaxVisibleCount = 100; |
| |
| /** |
| * flag that indicates if auto scaling on the y axis is enabled |
| */ |
| protected boolean mAutoScaleMinMaxEnabled = false; |
| |
| /** |
| * flag that indicates if pinch-zoom is enabled. if true, both x and y axis |
| * can be scaled with 2 fingers, if false, x and y axis can be scaled |
| * separately |
| */ |
| protected boolean mPinchZoomEnabled = false; |
| |
| /** |
| * flag that indicates if double tap zoom is enabled or not |
| */ |
| protected boolean mDoubleTapToZoomEnabled = true; |
| |
| /** |
| * flag that indicates if highlighting per dragging over a fully zoomed out |
| * chart is enabled |
| */ |
| protected boolean mHighlightPerDragEnabled = true; |
| |
| /** |
| * if true, dragging is enabled for the chart |
| */ |
| private boolean mDragXEnabled = true; |
| private boolean mDragYEnabled = true; |
| |
| private boolean mScaleXEnabled = true; |
| private boolean mScaleYEnabled = true; |
| |
| /** |
| * paint object for the (by default) lightgrey background of the grid |
| */ |
| protected Paint mGridBackgroundPaint; |
| |
| protected Paint mBorderPaint; |
| |
| /** |
| * flag indicating if the grid background should be drawn or not |
| */ |
| protected boolean mDrawGridBackground = false; |
| |
| protected boolean mDrawBorders = false; |
| |
| protected boolean mClipValuesToContent = false; |
| |
| /** |
| * Sets the minimum offset (padding) around the chart, defaults to 15 |
| */ |
| protected float mMinOffset = 15.f; |
| |
| /** |
| * flag indicating if the chart should stay at the same position after a rotation. Default is false. |
| */ |
| protected boolean mKeepPositionOnRotation = false; |
| |
| /** |
| * the listener for user drawing on the chart |
| */ |
| protected OnDrawListener mDrawListener; |
| |
| /** |
| * the object representing the labels on the left y-axis |
| */ |
| protected YAxis mAxisLeft; |
| |
| /** |
| * the object representing the labels on the right y-axis |
| */ |
| protected YAxis mAxisRight; |
| |
| protected YAxisRenderer mAxisRendererLeft; |
| protected YAxisRenderer mAxisRendererRight; |
| |
| protected Transformer mLeftAxisTransformer; |
| protected Transformer mRightAxisTransformer; |
| |
| protected XAxisRenderer mXAxisRenderer; |
| |
| // /** the approximator object used for data filtering */ |
| // private Approximator mApproximator; |
| |
| public BarLineChartBase(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| } |
| |
| public BarLineChartBase(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public BarLineChartBase(Context context) { |
| super(context); |
| } |
| |
| @Override |
| protected void init() { |
| super.init(); |
| |
| mAxisLeft = new YAxis(AxisDependency.LEFT); |
| mAxisRight = new YAxis(AxisDependency.RIGHT); |
| |
| mLeftAxisTransformer = new Transformer(mViewPortHandler); |
| mRightAxisTransformer = new Transformer(mViewPortHandler); |
| |
| mAxisRendererLeft = new YAxisRenderer(mViewPortHandler, mAxisLeft, mLeftAxisTransformer); |
| mAxisRendererRight = new YAxisRenderer(mViewPortHandler, mAxisRight, mRightAxisTransformer); |
| |
| mXAxisRenderer = new XAxisRenderer(mViewPortHandler, mXAxis, mLeftAxisTransformer); |
| |
| setHighlighter(new ChartHighlighter(this)); |
| |
| mChartTouchListener = new BarLineChartTouchListener(this, mViewPortHandler.getMatrixTouch(), 3f); |
| |
| mGridBackgroundPaint = new Paint(); |
| mGridBackgroundPaint.setStyle(Style.FILL); |
| // mGridBackgroundPaint.setColor(Color.WHITE); |
| mGridBackgroundPaint.setColor(Color.rgb(240, 240, 240)); // light |
| // grey |
| |
| mBorderPaint = new Paint(); |
| mBorderPaint.setStyle(Style.STROKE); |
| mBorderPaint.setColor(Color.BLACK); |
| mBorderPaint.setStrokeWidth(Utils.convertDpToPixel(1f)); |
| } |
| |
| // for performance tracking |
| private long totalTime = 0; |
| private long drawCycles = 0; |
| |
| @Override |
| protected void onDraw(Canvas canvas) { |
| super.onDraw(canvas); |
| |
| if (mData == null) |
| return; |
| |
| long starttime = System.currentTimeMillis(); |
| |
| // execute all drawing commands |
| drawGridBackground(canvas); |
| |
| if (mAutoScaleMinMaxEnabled) { |
| autoScale(); |
| } |
| |
| if (mAxisLeft.isEnabled()) |
| mAxisRendererLeft.computeAxis(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisMaximum, mAxisLeft.isInverted()); |
| |
| if (mAxisRight.isEnabled()) |
| mAxisRendererRight.computeAxis(mAxisRight.mAxisMinimum, mAxisRight.mAxisMaximum, mAxisRight.isInverted()); |
| |
| if (mXAxis.isEnabled()) |
| mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false); |
| |
| mXAxisRenderer.renderAxisLine(canvas); |
| mAxisRendererLeft.renderAxisLine(canvas); |
| mAxisRendererRight.renderAxisLine(canvas); |
| |
| mXAxisRenderer.renderGridLines(canvas); |
| mAxisRendererLeft.renderGridLines(canvas); |
| mAxisRendererRight.renderGridLines(canvas); |
| |
| if (mXAxis.isEnabled() && mXAxis.isDrawLimitLinesBehindDataEnabled()) |
| mXAxisRenderer.renderLimitLines(canvas); |
| |
| if (mAxisLeft.isEnabled() && mAxisLeft.isDrawLimitLinesBehindDataEnabled()) |
| mAxisRendererLeft.renderLimitLines(canvas); |
| |
| if (mAxisRight.isEnabled() && mAxisRight.isDrawLimitLinesBehindDataEnabled()) |
| mAxisRendererRight.renderLimitLines(canvas); |
| |
| // make sure the data cannot be drawn outside the content-rect |
| int clipRestoreCount = canvas.save(); |
| canvas.clipRect(mViewPortHandler.getContentRect()); |
| |
| mRenderer.drawData(canvas); |
| |
| // if highlighting is enabled |
| if (valuesToHighlight()) |
| mRenderer.drawHighlighted(canvas, mIndicesToHighlight); |
| |
| // Removes clipping rectangle |
| canvas.restoreToCount(clipRestoreCount); |
| |
| mRenderer.drawExtras(canvas); |
| |
| if (mXAxis.isEnabled() && !mXAxis.isDrawLimitLinesBehindDataEnabled()) |
| mXAxisRenderer.renderLimitLines(canvas); |
| |
| if (mAxisLeft.isEnabled() && !mAxisLeft.isDrawLimitLinesBehindDataEnabled()) |
| mAxisRendererLeft.renderLimitLines(canvas); |
| |
| if (mAxisRight.isEnabled() && !mAxisRight.isDrawLimitLinesBehindDataEnabled()) |
| mAxisRendererRight.renderLimitLines(canvas); |
| |
| mXAxisRenderer.renderAxisLabels(canvas); |
| mAxisRendererLeft.renderAxisLabels(canvas); |
| mAxisRendererRight.renderAxisLabels(canvas); |
| |
| if (isClipValuesToContentEnabled()) { |
| clipRestoreCount = canvas.save(); |
| canvas.clipRect(mViewPortHandler.getContentRect()); |
| |
| mRenderer.drawValues(canvas); |
| |
| canvas.restoreToCount(clipRestoreCount); |
| } else { |
| mRenderer.drawValues(canvas); |
| } |
| |
| mLegendRenderer.renderLegend(canvas); |
| |
| drawDescription(canvas); |
| |
| drawMarkers(canvas); |
| |
| if (mLogEnabled) { |
| long drawtime = (System.currentTimeMillis() - starttime); |
| totalTime += drawtime; |
| drawCycles += 1; |
| long average = totalTime / drawCycles; |
| Log.i(LOG_TAG, "Drawtime: " + drawtime + " ms, average: " + average + " ms, cycles: " |
| + drawCycles); |
| } |
| } |
| |
| /** |
| * RESET PERFORMANCE TRACKING FIELDS |
| */ |
| public void resetTracking() { |
| totalTime = 0; |
| drawCycles = 0; |
| } |
| |
| protected void prepareValuePxMatrix() { |
| |
| if (mLogEnabled) |
| Log.i(LOG_TAG, "Preparing Value-Px Matrix, xmin: " + mXAxis.mAxisMinimum + ", xmax: " |
| + mXAxis.mAxisMaximum + ", xdelta: " + mXAxis.mAxisRange); |
| |
| mRightAxisTransformer.prepareMatrixValuePx(mXAxis.mAxisMinimum, |
| mXAxis.mAxisRange, |
| mAxisRight.mAxisRange, |
| mAxisRight.mAxisMinimum); |
| mLeftAxisTransformer.prepareMatrixValuePx(mXAxis.mAxisMinimum, |
| mXAxis.mAxisRange, |
| mAxisLeft.mAxisRange, |
| mAxisLeft.mAxisMinimum); |
| } |
| |
| protected void prepareOffsetMatrix() { |
| |
| mRightAxisTransformer.prepareMatrixOffset(mAxisRight.isInverted()); |
| mLeftAxisTransformer.prepareMatrixOffset(mAxisLeft.isInverted()); |
| } |
| |
| @Override |
| public void notifyDataSetChanged() { |
| |
| if (mData == null) { |
| if (mLogEnabled) |
| Log.i(LOG_TAG, "Preparing... DATA NOT SET."); |
| return; |
| } else { |
| if (mLogEnabled) |
| Log.i(LOG_TAG, "Preparing..."); |
| } |
| |
| if (mRenderer != null) |
| mRenderer.initBuffers(); |
| |
| calcMinMax(); |
| |
| mAxisRendererLeft.computeAxis(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisMaximum, mAxisLeft.isInverted()); |
| mAxisRendererRight.computeAxis(mAxisRight.mAxisMinimum, mAxisRight.mAxisMaximum, mAxisRight.isInverted()); |
| mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false); |
| |
| if (mLegend != null) |
| mLegendRenderer.computeLegend(mData); |
| |
| calculateOffsets(); |
| } |
| |
| /** |
| * Performs auto scaling of the axis by recalculating the minimum and maximum y-values based on the entries currently in view. |
| */ |
| protected void autoScale() { |
| |
| final float fromX = getLowestVisibleX(); |
| final float toX = getHighestVisibleX(); |
| |
| mData.calcMinMaxY(fromX, toX); |
| |
| mXAxis.calculate(mData.getXMin(), mData.getXMax()); |
| |
| // calculate axis range (min / max) according to provided data |
| |
| if (mAxisLeft.isEnabled()) |
| mAxisLeft.calculate(mData.getYMin(AxisDependency.LEFT), |
| mData.getYMax(AxisDependency.LEFT)); |
| |
| if (mAxisRight.isEnabled()) |
| mAxisRight.calculate(mData.getYMin(AxisDependency.RIGHT), |
| mData.getYMax(AxisDependency.RIGHT)); |
| |
| calculateOffsets(); |
| } |
| |
| @Override |
| protected void calcMinMax() { |
| |
| mXAxis.calculate(mData.getXMin(), mData.getXMax()); |
| |
| // calculate axis range (min / max) according to provided data |
| mAxisLeft.calculate(mData.getYMin(AxisDependency.LEFT), mData.getYMax(AxisDependency.LEFT)); |
| mAxisRight.calculate(mData.getYMin(AxisDependency.RIGHT), mData.getYMax(AxisDependency |
| .RIGHT)); |
| } |
| |
| protected void calculateLegendOffsets(RectF offsets) { |
| |
| offsets.left = 0.f; |
| offsets.right = 0.f; |
| offsets.top = 0.f; |
| offsets.bottom = 0.f; |
| |
| // setup offsets for legend |
| if (mLegend != null && mLegend.isEnabled() && !mLegend.isDrawInsideEnabled()) { |
| switch (mLegend.getOrientation()) { |
| case VERTICAL: |
| |
| switch (mLegend.getHorizontalAlignment()) { |
| case LEFT: |
| offsets.left += Math.min(mLegend.mNeededWidth, |
| mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent()) |
| + mLegend.getXOffset(); |
| break; |
| |
| case RIGHT: |
| offsets.right += Math.min(mLegend.mNeededWidth, |
| mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent()) |
| + mLegend.getXOffset(); |
| break; |
| |
| case CENTER: |
| |
| switch (mLegend.getVerticalAlignment()) { |
| case TOP: |
| offsets.top += Math.min(mLegend.mNeededHeight, |
| mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) |
| + mLegend.getYOffset(); |
| break; |
| |
| case BOTTOM: |
| offsets.bottom += Math.min(mLegend.mNeededHeight, |
| mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) |
| + mLegend.getYOffset(); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| break; |
| |
| case HORIZONTAL: |
| |
| switch (mLegend.getVerticalAlignment()) { |
| case TOP: |
| offsets.top += Math.min(mLegend.mNeededHeight, |
| mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) |
| + mLegend.getYOffset(); |
| break; |
| |
| case BOTTOM: |
| offsets.bottom += Math.min(mLegend.mNeededHeight, |
| mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) |
| + mLegend.getYOffset(); |
| break; |
| |
| default: |
| break; |
| } |
| break; |
| } |
| } |
| } |
| |
| private RectF mOffsetsBuffer = new RectF(); |
| |
| @Override |
| public void calculateOffsets() { |
| |
| if (!mCustomViewPortEnabled) { |
| |
| float offsetLeft = 0f, offsetRight = 0f, offsetTop = 0f, offsetBottom = 0f; |
| |
| calculateLegendOffsets(mOffsetsBuffer); |
| |
| offsetLeft += mOffsetsBuffer.left; |
| offsetTop += mOffsetsBuffer.top; |
| offsetRight += mOffsetsBuffer.right; |
| offsetBottom += mOffsetsBuffer.bottom; |
| |
| // offsets for y-labels |
| if (mAxisLeft.needsOffset()) { |
| offsetLeft += mAxisLeft.getRequiredWidthSpace(mAxisRendererLeft |
| .getPaintAxisLabels()); |
| } |
| |
| if (mAxisRight.needsOffset()) { |
| offsetRight += mAxisRight.getRequiredWidthSpace(mAxisRendererRight |
| .getPaintAxisLabels()); |
| } |
| |
| if (mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled()) { |
| |
| float xLabelHeight = mXAxis.mLabelRotatedHeight + mXAxis.getYOffset(); |
| |
| // offsets for x-labels |
| if (mXAxis.getPosition() == XAxisPosition.BOTTOM) { |
| |
| offsetBottom += xLabelHeight; |
| |
| } else if (mXAxis.getPosition() == XAxisPosition.TOP) { |
| |
| offsetTop += xLabelHeight; |
| |
| } else if (mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) { |
| |
| offsetBottom += xLabelHeight; |
| offsetTop += xLabelHeight; |
| } |
| } |
| |
| offsetTop += getExtraTopOffset(); |
| offsetRight += getExtraRightOffset(); |
| offsetBottom += getExtraBottomOffset(); |
| offsetLeft += getExtraLeftOffset(); |
| |
| float minOffset = Utils.convertDpToPixel(mMinOffset); |
| |
| mViewPortHandler.restrainViewPort( |
| Math.max(minOffset, offsetLeft), |
| Math.max(minOffset, offsetTop), |
| Math.max(minOffset, offsetRight), |
| Math.max(minOffset, offsetBottom)); |
| |
| if (mLogEnabled) { |
| Log.i(LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop |
| + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom); |
| Log.i(LOG_TAG, "Content: " + mViewPortHandler.getContentRect().toString()); |
| } |
| } |
| |
| prepareOffsetMatrix(); |
| prepareValuePxMatrix(); |
| } |
| |
| /** |
| * draws the grid background |
| */ |
| protected void drawGridBackground(Canvas c) { |
| |
| if (mDrawGridBackground) { |
| |
| // draw the grid background |
| c.drawRect(mViewPortHandler.getContentRect(), mGridBackgroundPaint); |
| } |
| |
| if (mDrawBorders) { |
| c.drawRect(mViewPortHandler.getContentRect(), mBorderPaint); |
| } |
| } |
| |
| /** |
| * Returns the Transformer class that contains all matrices and is |
| * responsible for transforming values into pixels on the screen and |
| * backwards. |
| * |
| * @return |
| */ |
| public Transformer getTransformer(AxisDependency which) { |
| if (which == AxisDependency.LEFT) |
| return mLeftAxisTransformer; |
| else |
| return mRightAxisTransformer; |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent event) { |
| super.onTouchEvent(event); |
| |
| if (mChartTouchListener == null || mData == null) |
| return false; |
| |
| // check if touch gestures are enabled |
| if (!mTouchEnabled) |
| return false; |
| else |
| return mChartTouchListener.onTouch(this, event); |
| } |
| |
| @Override |
| public void computeScroll() { |
| |
| if (mChartTouchListener instanceof BarLineChartTouchListener) |
| ((BarLineChartTouchListener) mChartTouchListener).computeScroll(); |
| } |
| |
| /** |
| * ################ ################ ################ ################ |
| */ |
| /** |
| * CODE BELOW THIS RELATED TO SCALING AND GESTURES AND MODIFICATION OF THE |
| * VIEWPORT |
| */ |
| |
| protected Matrix mZoomMatrixBuffer = new Matrix(); |
| |
| /** |
| * Zooms in by 1.4f, into the charts center. |
| */ |
| public void zoomIn() { |
| |
| MPPointF center = mViewPortHandler.getContentCenter(); |
| |
| mViewPortHandler.zoomIn(center.x, -center.y, mZoomMatrixBuffer); |
| mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); |
| |
| MPPointF.recycleInstance(center); |
| |
| // Range might have changed, which means that Y-axis labels |
| // could have changed in size, affecting Y-axis size. |
| // So we need to recalculate offsets. |
| calculateOffsets(); |
| postInvalidate(); |
| } |
| |
| /** |
| * Zooms out by 0.7f, from the charts center. |
| */ |
| public void zoomOut() { |
| |
| MPPointF center = mViewPortHandler.getContentCenter(); |
| |
| mViewPortHandler.zoomOut(center.x, -center.y, mZoomMatrixBuffer); |
| mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); |
| |
| MPPointF.recycleInstance(center); |
| |
| // Range might have changed, which means that Y-axis labels |
| // could have changed in size, affecting Y-axis size. |
| // So we need to recalculate offsets. |
| calculateOffsets(); |
| postInvalidate(); |
| } |
| |
| /** |
| * Zooms out to original size. |
| */ |
| public void resetZoom() { |
| |
| mViewPortHandler.resetZoom(mZoomMatrixBuffer); |
| mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); |
| |
| // Range might have changed, which means that Y-axis labels |
| // could have changed in size, affecting Y-axis size. |
| // So we need to recalculate offsets. |
| calculateOffsets(); |
| postInvalidate(); |
| } |
| |
| /** |
| * Zooms in or out by the given scale factor. x and y are the coordinates |
| * (in pixels) of the zoom center. |
| * |
| * @param scaleX if < 1f --> zoom out, if > 1f --> zoom in |
| * @param scaleY if < 1f --> zoom out, if > 1f --> zoom in |
| * @param x |
| * @param y |
| */ |
| public void zoom(float scaleX, float scaleY, float x, float y) { |
| |
| mViewPortHandler.zoom(scaleX, scaleY, x, -y, mZoomMatrixBuffer); |
| mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); |
| |
| // Range might have changed, which means that Y-axis labels |
| // could have changed in size, affecting Y-axis size. |
| // So we need to recalculate offsets. |
| calculateOffsets(); |
| postInvalidate(); |
| } |
| |
| /** |
| * Zooms in or out by the given scale factor. |
| * x and y are the values (NOT PIXELS) of the zoom center.. |
| * |
| * @param scaleX |
| * @param scaleY |
| * @param xValue |
| * @param yValue |
| * @param axis the axis relative to which the zoom should take place |
| */ |
| public void zoom(float scaleX, float scaleY, float xValue, float yValue, AxisDependency axis) { |
| |
| Runnable job = ZoomJob.getInstance(mViewPortHandler, scaleX, scaleY, xValue, yValue, getTransformer(axis), axis, this); |
| addViewportJob(job); |
| } |
| |
| /** |
| * Zooms to the center of the chart with the given scale factor. |
| * |
| * @param scaleX |
| * @param scaleY |
| */ |
| public void zoomToCenter(float scaleX, float scaleY) { |
| |
| MPPointF center = getCenterOffsets(); |
| |
| Matrix save = mZoomMatrixBuffer; |
| mViewPortHandler.zoom(scaleX, scaleY, center.x, -center.y, save); |
| mViewPortHandler.refresh(save, this, false); |
| } |
| |
| /** |
| * Zooms by the specified scale factor to the specified values on the specified axis. |
| * |
| * @param scaleX |
| * @param scaleY |
| * @param xValue |
| * @param yValue |
| * @param axis |
| * @param duration |
| */ |
| @TargetApi(11) |
| public void zoomAndCenterAnimated(float scaleX, float scaleY, float xValue, float yValue, AxisDependency axis, |
| long duration) { |
| |
| if (android.os.Build.VERSION.SDK_INT >= 11) { |
| |
| MPPointD origin = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis); |
| |
| Runnable job = AnimatedZoomJob.getInstance(mViewPortHandler, this, getTransformer(axis), getAxis(axis), mXAxis |
| .mAxisRange, scaleX, scaleY, mViewPortHandler.getScaleX(), mViewPortHandler.getScaleY(), |
| xValue, yValue, (float) origin.x, (float) origin.y, duration); |
| addViewportJob(job); |
| |
| MPPointD.recycleInstance(origin); |
| |
| } else { |
| Log.e(LOG_TAG, "Unable to execute zoomAndCenterAnimated(...) on API level < 11"); |
| } |
| } |
| |
| protected Matrix mFitScreenMatrixBuffer = new Matrix(); |
| |
| /** |
| * Resets all zooming and dragging and makes the chart fit exactly it's |
| * bounds. |
| */ |
| public void fitScreen() { |
| Matrix save = mFitScreenMatrixBuffer; |
| mViewPortHandler.fitScreen(save); |
| mViewPortHandler.refresh(save, this, false); |
| |
| calculateOffsets(); |
| postInvalidate(); |
| } |
| |
| /** |
| * Sets the minimum scale factor value to which can be zoomed out. 1f = |
| * fitScreen |
| * |
| * @param scaleX |
| * @param scaleY |
| */ |
| public void setScaleMinima(float scaleX, float scaleY) { |
| mViewPortHandler.setMinimumScaleX(scaleX); |
| mViewPortHandler.setMinimumScaleY(scaleY); |
| } |
| |
| /** |
| * Sets the size of the area (range on the x-axis) that should be maximum |
| * visible at once (no further zooming out allowed). If this is e.g. set to |
| * 10, no more than a range of 10 on the x-axis can be viewed at once without |
| * scrolling. |
| * |
| * @param maxXRange The maximum visible range of x-values. |
| */ |
| public void setVisibleXRangeMaximum(float maxXRange) { |
| float xScale = mXAxis.mAxisRange / (maxXRange); |
| mViewPortHandler.setMinimumScaleX(xScale); |
| } |
| |
| /** |
| * Sets the size of the area (range on the x-axis) that should be minimum |
| * visible at once (no further zooming in allowed). If this is e.g. set to |
| * 10, no less than a range of 10 on the x-axis can be viewed at once without |
| * scrolling. |
| * |
| * @param minXRange The minimum visible range of x-values. |
| */ |
| public void setVisibleXRangeMinimum(float minXRange) { |
| float xScale = mXAxis.mAxisRange / (minXRange); |
| mViewPortHandler.setMaximumScaleX(xScale); |
| } |
| |
| /** |
| * Limits the maximum and minimum x range that can be visible by pinching and zooming. e.g. minRange=10, maxRange=100 the |
| * smallest range to be displayed at once is 10, and no more than a range of 100 values can be viewed at once without |
| * scrolling |
| * |
| * @param minXRange |
| * @param maxXRange |
| */ |
| public void setVisibleXRange(float minXRange, float maxXRange) { |
| float minScale = mXAxis.mAxisRange / minXRange; |
| float maxScale = mXAxis.mAxisRange / maxXRange; |
| mViewPortHandler.setMinMaxScaleX(minScale, maxScale); |
| } |
| |
| /** |
| * Sets the size of the area (range on the y-axis) that should be maximum |
| * visible at once. |
| * |
| * @param maxYRange the maximum visible range on the y-axis |
| * @param axis the axis for which this limit should apply |
| */ |
| public void setVisibleYRangeMaximum(float maxYRange, AxisDependency axis) { |
| float yScale = getAxisRange(axis) / maxYRange; |
| mViewPortHandler.setMinimumScaleY(yScale); |
| } |
| |
| /** |
| * Sets the size of the area (range on the y-axis) that should be minimum visible at once, no further zooming in possible. |
| * |
| * @param minYRange |
| * @param axis the axis for which this limit should apply |
| */ |
| public void setVisibleYRangeMinimum(float minYRange, AxisDependency axis) { |
| float yScale = getAxisRange(axis) / minYRange; |
| mViewPortHandler.setMaximumScaleY(yScale); |
| } |
| |
| /** |
| * Limits the maximum and minimum y range that can be visible by pinching and zooming. |
| * |
| * @param minYRange |
| * @param maxYRange |
| * @param axis |
| */ |
| public void setVisibleYRange(float minYRange, float maxYRange, AxisDependency axis) { |
| float minScale = getAxisRange(axis) / minYRange; |
| float maxScale = getAxisRange(axis) / maxYRange; |
| mViewPortHandler.setMinMaxScaleY(minScale, maxScale); |
| } |
| |
| |
| /** |
| * Moves the left side of the current viewport to the specified x-position. |
| * This also refreshes the chart by calling invalidate(). |
| * |
| * @param xValue |
| */ |
| public void moveViewToX(float xValue) { |
| |
| Runnable job = MoveViewJob.getInstance(mViewPortHandler, xValue, 0f, |
| getTransformer(AxisDependency.LEFT), this); |
| |
| addViewportJob(job); |
| } |
| |
| /** |
| * This will move the left side of the current viewport to the specified |
| * x-value on the x-axis, and center the viewport to the specified y value on the y-axis. |
| * This also refreshes the chart by calling invalidate(). |
| * |
| * @param xValue |
| * @param yValue |
| * @param axis - which axis should be used as a reference for the y-axis |
| */ |
| public void moveViewTo(float xValue, float yValue, AxisDependency axis) { |
| |
| float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); |
| |
| Runnable job = MoveViewJob.getInstance(mViewPortHandler, xValue, yValue + yInView / 2f, |
| getTransformer(axis), this); |
| |
| addViewportJob(job); |
| } |
| |
| /** |
| * This will move the left side of the current viewport to the specified x-value |
| * and center the viewport to the y value animated. |
| * This also refreshes the chart by calling invalidate(). |
| * |
| * @param xValue |
| * @param yValue |
| * @param axis |
| * @param duration the duration of the animation in milliseconds |
| */ |
| @TargetApi(11) |
| public void moveViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) { |
| |
| if (android.os.Build.VERSION.SDK_INT >= 11) { |
| |
| MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis); |
| |
| float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); |
| |
| Runnable job = AnimatedMoveViewJob.getInstance(mViewPortHandler, xValue, yValue + yInView / 2f, |
| getTransformer(axis), this, (float) bounds.x, (float) bounds.y, duration); |
| |
| addViewportJob(job); |
| |
| MPPointD.recycleInstance(bounds); |
| } else { |
| Log.e(LOG_TAG, "Unable to execute moveViewToAnimated(...) on API level < 11"); |
| } |
| } |
| |
| /** |
| * Centers the viewport to the specified y value on the y-axis. |
| * This also refreshes the chart by calling invalidate(). |
| * |
| * @param yValue |
| * @param axis - which axis should be used as a reference for the y-axis |
| */ |
| public void centerViewToY(float yValue, AxisDependency axis) { |
| |
| float valsInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); |
| |
| Runnable job = MoveViewJob.getInstance(mViewPortHandler, 0f, yValue + valsInView / 2f, |
| getTransformer(axis), this); |
| |
| addViewportJob(job); |
| } |
| |
| /** |
| * This will move the center of the current viewport to the specified |
| * x and y value. |
| * This also refreshes the chart by calling invalidate(). |
| * |
| * @param xValue |
| * @param yValue |
| * @param axis - which axis should be used as a reference for the y axis |
| */ |
| public void centerViewTo(float xValue, float yValue, AxisDependency axis) { |
| |
| float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); |
| float xInView = getXAxis().mAxisRange / mViewPortHandler.getScaleX(); |
| |
| Runnable job = MoveViewJob.getInstance(mViewPortHandler, |
| xValue - xInView / 2f, yValue + yInView / 2f, |
| getTransformer(axis), this); |
| |
| addViewportJob(job); |
| } |
| |
| /** |
| * This will move the center of the current viewport to the specified |
| * x and y value animated. |
| * |
| * @param xValue |
| * @param yValue |
| * @param axis |
| * @param duration the duration of the animation in milliseconds |
| */ |
| @TargetApi(11) |
| public void centerViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) { |
| |
| if (android.os.Build.VERSION.SDK_INT >= 11) { |
| |
| MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis); |
| |
| float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); |
| float xInView = getXAxis().mAxisRange / mViewPortHandler.getScaleX(); |
| |
| Runnable job = AnimatedMoveViewJob.getInstance(mViewPortHandler, |
| xValue - xInView / 2f, yValue + yInView / 2f, |
| getTransformer(axis), this, (float) bounds.x, (float) bounds.y, duration); |
| |
| addViewportJob(job); |
| |
| MPPointD.recycleInstance(bounds); |
| } else { |
| Log.e(LOG_TAG, "Unable to execute centerViewToAnimated(...) on API level < 11"); |
| } |
| } |
| |
| /** |
| * flag that indicates if a custom viewport offset has been set |
| */ |
| private boolean mCustomViewPortEnabled = false; |
| |
| /** |
| * Sets custom offsets for the current ViewPort (the offsets on the sides of |
| * the actual chart window). Setting this will prevent the chart from |
| * automatically calculating it's offsets. Use resetViewPortOffsets() to |
| * undo this. ONLY USE THIS WHEN YOU KNOW WHAT YOU ARE DOING, else use |
| * setExtraOffsets(...). |
| * |
| * @param left |
| * @param top |
| * @param right |
| * @param bottom |
| */ |
| public void setViewPortOffsets(final float left, final float top, |
| final float right, final float bottom) { |
| |
| mCustomViewPortEnabled = true; |
| post(new Runnable() { |
| |
| @Override |
| public void run() { |
| |
| mViewPortHandler.restrainViewPort(left, top, right, bottom); |
| prepareOffsetMatrix(); |
| prepareValuePxMatrix(); |
| } |
| }); |
| } |
| |
| /** |
| * Resets all custom offsets set via setViewPortOffsets(...) method. Allows |
| * the chart to again calculate all offsets automatically. |
| */ |
| public void resetViewPortOffsets() { |
| mCustomViewPortEnabled = false; |
| calculateOffsets(); |
| } |
| |
| /** |
| * ################ ################ ################ ################ |
| */ |
| /** CODE BELOW IS GETTERS AND SETTERS */ |
| |
| /** |
| * Returns the range of the specified axis. |
| * |
| * @param axis |
| * @return |
| */ |
| protected float getAxisRange(AxisDependency axis) { |
| if (axis == AxisDependency.LEFT) |
| return mAxisLeft.mAxisRange; |
| else |
| return mAxisRight.mAxisRange; |
| } |
| |
| /** |
| * Sets the OnDrawListener |
| * |
| * @param drawListener |
| */ |
| public void setOnDrawListener(OnDrawListener drawListener) { |
| this.mDrawListener = drawListener; |
| } |
| |
| /** |
| * Gets the OnDrawListener. May be null. |
| * |
| * @return |
| */ |
| public OnDrawListener getDrawListener() { |
| return mDrawListener; |
| } |
| |
| protected float[] mGetPositionBuffer = new float[2]; |
| |
| /** |
| * Returns a recyclable MPPointF instance. |
| * Returns the position (in pixels) the provided Entry has inside the chart |
| * view or null, if the provided Entry is null. |
| * |
| * @param e |
| * @return |
| */ |
| public MPPointF getPosition(Entry e, AxisDependency axis) { |
| |
| if (e == null) |
| return null; |
| |
| mGetPositionBuffer[0] = e.getX(); |
| mGetPositionBuffer[1] = e.getY(); |
| |
| getTransformer(axis).pointValuesToPixel(mGetPositionBuffer); |
| |
| return MPPointF.getInstance(mGetPositionBuffer[0], mGetPositionBuffer[1]); |
| } |
| |
| /** |
| * sets the number of maximum visible drawn values on the chart only active |
| * when setDrawValues() is enabled |
| * |
| * @param count |
| */ |
| public void setMaxVisibleValueCount(int count) { |
| this.mMaxVisibleCount = count; |
| } |
| |
| public int getMaxVisibleCount() { |
| return mMaxVisibleCount; |
| } |
| |
| /** |
| * Set this to true to allow highlighting per dragging over the chart |
| * surface when it is fully zoomed out. Default: true |
| * |
| * @param enabled |
| */ |
| public void setHighlightPerDragEnabled(boolean enabled) { |
| mHighlightPerDragEnabled = enabled; |
| } |
| |
| public boolean isHighlightPerDragEnabled() { |
| return mHighlightPerDragEnabled; |
| } |
| |
| /** |
| * Sets the color for the background of the chart-drawing area (everything |
| * behind the grid lines). |
| * |
| * @param color |
| */ |
| public void setGridBackgroundColor(int color) { |
| mGridBackgroundPaint.setColor(color); |
| } |
| |
| /** |
| * Set this to true to enable dragging (moving the chart with the finger) |
| * for the chart (this does not effect scaling). |
| * |
| * @param enabled |
| */ |
| public void setDragEnabled(boolean enabled) { |
| this.mDragXEnabled = enabled; |
| this.mDragYEnabled = enabled; |
| } |
| |
| /** |
| * Returns true if dragging is enabled for the chart, false if not. |
| * |
| * @return |
| */ |
| public boolean isDragEnabled() { |
| return mDragXEnabled || mDragYEnabled; |
| } |
| |
| /** |
| * Set this to true to enable dragging on the X axis |
| * |
| * @param enabled |
| */ |
| public void setDragXEnabled(boolean enabled) { |
| this.mDragXEnabled = enabled; |
| } |
| |
| /** |
| * Returns true if dragging on the X axis is enabled for the chart, false if not. |
| * |
| * @return |
| */ |
| public boolean isDragXEnabled() { |
| return mDragXEnabled; |
| } |
| |
| /** |
| * Set this to true to enable dragging on the Y axis |
| * |
| * @param enabled |
| */ |
| public void setDragYEnabled(boolean enabled) { |
| this.mDragYEnabled = enabled; |
| } |
| |
| /** |
| * Returns true if dragging on the Y axis is enabled for the chart, false if not. |
| * |
| * @return |
| */ |
| public boolean isDragYEnabled() { |
| return mDragYEnabled; |
| } |
| |
| /** |
| * Set this to true to enable scaling (zooming in and out by gesture) for |
| * the chart (this does not effect dragging) on both X- and Y-Axis. |
| * |
| * @param enabled |
| */ |
| public void setScaleEnabled(boolean enabled) { |
| this.mScaleXEnabled = enabled; |
| this.mScaleYEnabled = enabled; |
| } |
| |
| public void setScaleXEnabled(boolean enabled) { |
| mScaleXEnabled = enabled; |
| } |
| |
| public void setScaleYEnabled(boolean enabled) { |
| mScaleYEnabled = enabled; |
| } |
| |
| public boolean isScaleXEnabled() { |
| return mScaleXEnabled; |
| } |
| |
| public boolean isScaleYEnabled() { |
| return mScaleYEnabled; |
| } |
| |
| /** |
| * Set this to true to enable zooming in by double-tap on the chart. |
| * Default: enabled |
| * |
| * @param enabled |
| */ |
| public void setDoubleTapToZoomEnabled(boolean enabled) { |
| mDoubleTapToZoomEnabled = enabled; |
| } |
| |
| /** |
| * Returns true if zooming via double-tap is enabled false if not. |
| * |
| * @return |
| */ |
| public boolean isDoubleTapToZoomEnabled() { |
| return mDoubleTapToZoomEnabled; |
| } |
| |
| /** |
| * set this to true to draw the grid background, false if not |
| * |
| * @param enabled |
| */ |
| public void setDrawGridBackground(boolean enabled) { |
| mDrawGridBackground = enabled; |
| } |
| |
| /** |
| * When enabled, the borders rectangle will be rendered. |
| * If this is enabled, there is no point drawing the axis-lines of x- and y-axis. |
| * |
| * @param enabled |
| */ |
| public void setDrawBorders(boolean enabled) { |
| mDrawBorders = enabled; |
| } |
| |
| /** |
| * When enabled, the borders rectangle will be rendered. |
| * If this is enabled, there is no point drawing the axis-lines of x- and y-axis. |
| * |
| * @return |
| */ |
| public boolean isDrawBordersEnabled() { |
| return mDrawBorders; |
| } |
| |
| /** |
| * When enabled, the values will be clipped to contentRect, |
| * otherwise they can bleed outside the content rect. |
| * |
| * @param enabled |
| */ |
| public void setClipValuesToContent(boolean enabled) { |
| mClipValuesToContent = enabled; |
| } |
| |
| /** |
| * When enabled, the values will be clipped to contentRect, |
| * otherwise they can bleed outside the content rect. |
| * |
| * @return |
| */ |
| public boolean isClipValuesToContentEnabled() { |
| return mClipValuesToContent; |
| } |
| |
| /** |
| * Sets the width of the border lines in dp. |
| * |
| * @param width |
| */ |
| public void setBorderWidth(float width) { |
| mBorderPaint.setStrokeWidth(Utils.convertDpToPixel(width)); |
| } |
| |
| /** |
| * Sets the color of the chart border lines. |
| * |
| * @param color |
| */ |
| public void setBorderColor(int color) { |
| mBorderPaint.setColor(color); |
| } |
| |
| /** |
| * Gets the minimum offset (padding) around the chart, defaults to 15.f |
| */ |
| public float getMinOffset() { |
| return mMinOffset; |
| } |
| |
| /** |
| * Sets the minimum offset (padding) around the chart, defaults to 15.f |
| */ |
| public void setMinOffset(float minOffset) { |
| mMinOffset = minOffset; |
| } |
| |
| /** |
| * Returns true if keeping the position on rotation is enabled and false if not. |
| */ |
| public boolean isKeepPositionOnRotation() { |
| return mKeepPositionOnRotation; |
| } |
| |
| /** |
| * Sets whether the chart should keep its position (zoom / scroll) after a rotation (orientation change) |
| */ |
| public void setKeepPositionOnRotation(boolean keepPositionOnRotation) { |
| mKeepPositionOnRotation = keepPositionOnRotation; |
| } |
| |
| /** |
| * Returns a recyclable MPPointD instance |
| * Returns the x and y values in the chart at the given touch point |
| * (encapsulated in a MPPointD). This method transforms pixel coordinates to |
| * coordinates / values in the chart. This is the opposite method to |
| * getPixelForValues(...). |
| * |
| * @param x |
| * @param y |
| * @return |
| */ |
| public MPPointD getValuesByTouchPoint(float x, float y, AxisDependency axis) { |
| MPPointD result = MPPointD.getInstance(0, 0); |
| getValuesByTouchPoint(x, y, axis, result); |
| return result; |
| } |
| |
| public void getValuesByTouchPoint(float x, float y, AxisDependency axis, MPPointD outputPoint) { |
| getTransformer(axis).getValuesByTouchPoint(x, y, outputPoint); |
| } |
| |
| /** |
| * Returns a recyclable MPPointD instance |
| * Transforms the given chart values into pixels. This is the opposite |
| * method to getValuesByTouchPoint(...). |
| * |
| * @param x |
| * @param y |
| * @return |
| */ |
| public MPPointD getPixelForValues(float x, float y, AxisDependency axis) { |
| return getTransformer(axis).getPixelForValues(x, y); |
| } |
| |
| /** |
| * returns the Entry object displayed at the touched position of the chart |
| * |
| * @param x |
| * @param y |
| * @return |
| */ |
| public Entry getEntryByTouchPoint(float x, float y) { |
| Highlight h = getHighlightByTouchPoint(x, y); |
| if (h != null) { |
| return mData.getEntryForHighlight(h); |
| } |
| return null; |
| } |
| |
| /** |
| * returns the DataSet object displayed at the touched position of the chart |
| * |
| * @param x |
| * @param y |
| * @return |
| */ |
| public IBarLineScatterCandleBubbleDataSet getDataSetByTouchPoint(float x, float y) { |
| Highlight h = getHighlightByTouchPoint(x, y); |
| if (h != null) { |
| return mData.getDataSetByIndex(h.getDataSetIndex()); |
| } |
| return null; |
| } |
| |
| /** |
| * buffer for storing lowest visible x point |
| */ |
| protected MPPointD posForGetLowestVisibleX = MPPointD.getInstance(0, 0); |
| |
| /** |
| * Returns the lowest x-index (value on the x-axis) that is still visible on |
| * the chart. |
| * |
| * @return |
| */ |
| @Override |
| public float getLowestVisibleX() { |
| getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(), |
| mViewPortHandler.contentBottom(), posForGetLowestVisibleX); |
| float result = (float) Math.max(mXAxis.mAxisMinimum, posForGetLowestVisibleX.x); |
| return result; |
| } |
| |
| /** |
| * buffer for storing highest visible x point |
| */ |
| protected MPPointD posForGetHighestVisibleX = MPPointD.getInstance(0, 0); |
| |
| /** |
| * Returns the highest x-index (value on the x-axis) that is still visible |
| * on the chart. |
| * |
| * @return |
| */ |
| @Override |
| public float getHighestVisibleX() { |
| getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentRight(), |
| mViewPortHandler.contentBottom(), posForGetHighestVisibleX); |
| float result = (float) Math.min(mXAxis.mAxisMaximum, posForGetHighestVisibleX.x); |
| return result; |
| } |
| |
| /** |
| * Returns the range visible on the x-axis. |
| * |
| * @return |
| */ |
| public float getVisibleXRange() { |
| return Math.abs(getHighestVisibleX() - getLowestVisibleX()); |
| } |
| |
| /** |
| * returns the current x-scale factor |
| */ |
| public float getScaleX() { |
| if (mViewPortHandler == null) |
| return 1f; |
| else |
| return mViewPortHandler.getScaleX(); |
| } |
| |
| /** |
| * returns the current y-scale factor |
| */ |
| public float getScaleY() { |
| if (mViewPortHandler == null) |
| return 1f; |
| else |
| return mViewPortHandler.getScaleY(); |
| } |
| |
| /** |
| * if the chart is fully zoomed out, return true |
| * |
| * @return |
| */ |
| public boolean isFullyZoomedOut() { |
| return mViewPortHandler.isFullyZoomedOut(); |
| } |
| |
| /** |
| * Returns the left y-axis object. In the horizontal bar-chart, this is the |
| * top axis. |
| * |
| * @return |
| */ |
| public YAxis getAxisLeft() { |
| return mAxisLeft; |
| } |
| |
| /** |
| * Returns the right y-axis object. In the horizontal bar-chart, this is the |
| * bottom axis. |
| * |
| * @return |
| */ |
| public YAxis getAxisRight() { |
| return mAxisRight; |
| } |
| |
| /** |
| * Returns the y-axis object to the corresponding AxisDependency. In the |
| * horizontal bar-chart, LEFT == top, RIGHT == BOTTOM |
| * |
| * @param axis |
| * @return |
| */ |
| public YAxis getAxis(AxisDependency axis) { |
| if (axis == AxisDependency.LEFT) |
| return mAxisLeft; |
| else |
| return mAxisRight; |
| } |
| |
| @Override |
| public boolean isInverted(AxisDependency axis) { |
| return getAxis(axis).isInverted(); |
| } |
| |
| /** |
| * If set to true, both x and y axis can be scaled simultaneously with 2 fingers, if false, |
| * x and y axis can be scaled separately. default: false |
| * |
| * @param enabled |
| */ |
| public void setPinchZoom(boolean enabled) { |
| mPinchZoomEnabled = enabled; |
| } |
| |
| /** |
| * returns true if pinch-zoom is enabled, false if not |
| * |
| * @return |
| */ |
| public boolean isPinchZoomEnabled() { |
| return mPinchZoomEnabled; |
| } |
| |
| /** |
| * Set an offset in dp that allows the user to drag the chart over it's |
| * bounds on the x-axis. |
| * |
| * @param offset |
| */ |
| public void setDragOffsetX(float offset) { |
| mViewPortHandler.setDragOffsetX(offset); |
| } |
| |
| /** |
| * Set an offset in dp that allows the user to drag the chart over it's |
| * bounds on the y-axis. |
| * |
| * @param offset |
| */ |
| public void setDragOffsetY(float offset) { |
| mViewPortHandler.setDragOffsetY(offset); |
| } |
| |
| /** |
| * Returns true if both drag offsets (x and y) are zero or smaller. |
| * |
| * @return |
| */ |
| public boolean hasNoDragOffset() { |
| return mViewPortHandler.hasNoDragOffset(); |
| } |
| |
| public XAxisRenderer getRendererXAxis() { |
| return mXAxisRenderer; |
| } |
| |
| /** |
| * Sets a custom XAxisRenderer and overrides the existing (default) one. |
| * |
| * @param xAxisRenderer |
| */ |
| public void setXAxisRenderer(XAxisRenderer xAxisRenderer) { |
| mXAxisRenderer = xAxisRenderer; |
| } |
| |
| public YAxisRenderer getRendererLeftYAxis() { |
| return mAxisRendererLeft; |
| } |
| |
| /** |
| * Sets a custom axis renderer for the left axis and overwrites the existing one. |
| * |
| * @param rendererLeftYAxis |
| */ |
| public void setRendererLeftYAxis(YAxisRenderer rendererLeftYAxis) { |
| mAxisRendererLeft = rendererLeftYAxis; |
| } |
| |
| public YAxisRenderer getRendererRightYAxis() { |
| return mAxisRendererRight; |
| } |
| |
| /** |
| * Sets a custom axis renderer for the right acis and overwrites the existing one. |
| * |
| * @param rendererRightYAxis |
| */ |
| public void setRendererRightYAxis(YAxisRenderer rendererRightYAxis) { |
| mAxisRendererRight = rendererRightYAxis; |
| } |
| |
| @Override |
| public float getYChartMax() { |
| return Math.max(mAxisLeft.mAxisMaximum, mAxisRight.mAxisMaximum); |
| } |
| |
| @Override |
| public float getYChartMin() { |
| return Math.min(mAxisLeft.mAxisMinimum, mAxisRight.mAxisMinimum); |
| } |
| |
| /** |
| * Returns true if either the left or the right or both axes are inverted. |
| * |
| * @return |
| */ |
| public boolean isAnyAxisInverted() { |
| if (mAxisLeft.isInverted()) |
| return true; |
| if (mAxisRight.isInverted()) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Flag that indicates if auto scaling on the y axis is enabled. This is |
| * especially interesting for charts displaying financial data. |
| * |
| * @param enabled the y axis automatically adjusts to the min and max y |
| * values of the current x axis range whenever the viewport |
| * changes |
| */ |
| public void setAutoScaleMinMaxEnabled(boolean enabled) { |
| mAutoScaleMinMaxEnabled = enabled; |
| } |
| |
| /** |
| * @return true if auto scaling on the y axis is enabled. |
| * @default false |
| */ |
| public boolean isAutoScaleMinMaxEnabled() { |
| return mAutoScaleMinMaxEnabled; |
| } |
| |
| @Override |
| public void setPaint(Paint p, int which) { |
| super.setPaint(p, which); |
| |
| switch (which) { |
| case PAINT_GRID_BACKGROUND: |
| mGridBackgroundPaint = p; |
| break; |
| } |
| } |
| |
| @Override |
| public Paint getPaint(int which) { |
| Paint p = super.getPaint(which); |
| if (p != null) |
| return p; |
| |
| switch (which) { |
| case PAINT_GRID_BACKGROUND: |
| return mGridBackgroundPaint; |
| } |
| |
| return null; |
| } |
| |
| protected float[] mOnSizeChangedBuffer = new float[2]; |
| |
| @Override |
| protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
| |
| // Saving current position of chart. |
| mOnSizeChangedBuffer[0] = mOnSizeChangedBuffer[1] = 0; |
| |
| if (mKeepPositionOnRotation) { |
| mOnSizeChangedBuffer[0] = mViewPortHandler.contentLeft(); |
| mOnSizeChangedBuffer[1] = mViewPortHandler.contentTop(); |
| getTransformer(AxisDependency.LEFT).pixelsToValue(mOnSizeChangedBuffer); |
| } |
| |
| //Superclass transforms chart. |
| super.onSizeChanged(w, h, oldw, oldh); |
| |
| if (mKeepPositionOnRotation) { |
| |
| //Restoring old position of chart. |
| getTransformer(AxisDependency.LEFT).pointValuesToPixel(mOnSizeChangedBuffer); |
| mViewPortHandler.centerViewPort(mOnSizeChangedBuffer, this); |
| } else { |
| mViewPortHandler.refresh(mViewPortHandler.getMatrixTouch(), this, true); |
| } |
| } |
| } |