diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarChart.kt index 14815cac7..6116e5c83 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarChart.kt @@ -187,7 +187,7 @@ open class BarChart : BarLineChartBase, BarDataProvider { outputRect.set(left, top, right, bottom) - getTransformer(set.axisDependency)!!.rectValueToPixel(outputRect) + getTransformer(set.axisDependency).rectValueToPixel(outputRect) } } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.java b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.java deleted file mode 100644 index bf8e000b5..000000000 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.java +++ /dev/null @@ -1,1519 +0,0 @@ -package com.github.mikephil.charting.charts; - -import android.annotation.SuppressLint; -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.base.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.UtilsKtKt; - -import androidx.annotation.NonNull; - -/** - * Base-class of LineChart, BarChart, ScatterChart and CandleStickChart. - * - * @author Philipp Jahoda - */ -@SuppressWarnings("unused") -@SuppressLint("RtlHardcoded") -public abstract class BarLineChartBase>> extends Chart 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; - - /** - * if true, fling gesture is enabled for the chart - */ - private boolean mFlingEnabled = false; - - /** - * 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; - - protected boolean mClipDataToContent = true; - - /** - * 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(getViewPortHandler()); - mRightAxisTransformer = new Transformer(getViewPortHandler()); - - mAxisRendererLeft = new YAxisRenderer(getViewPortHandler(), mAxisLeft, mLeftAxisTransformer); - mAxisRendererRight = new YAxisRenderer(getViewPortHandler(), mAxisRight, mRightAxisTransformer); - - mXAxisRenderer = new XAxisRenderer(getViewPortHandler(), mXAxis, mLeftAxisTransformer); - - setHighlighter(new ChartHighlighter<>(this)); - - mChartTouchListener = new BarLineChartTouchListener(this, getViewPortHandler().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(UtilsKtKt.convertDpToPixel(1f)); - } - - // for performance tracking - private long totalTime = 0; - private long drawCycles = 0; - - @Override - protected void onDraw(@NonNull 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); - } - - // Y-axis labels could have changed in size affecting the offsets - if (mAutoScaleMinMaxEnabled) { - calculateOffsets(); - getViewPortHandler().refresh(getViewPortHandler().getMatrixTouch(), this, false); - } - - mXAxisRenderer.renderAxisLine(canvas); - mAxisRendererLeft.renderAxisLine(canvas); - mAxisRendererRight.renderAxisLine(canvas); - - if (mXAxis.isDrawGridLinesBehindDataEnabled()) { - mXAxisRenderer.renderGridLines(canvas); - } - - if (mAxisLeft.isDrawGridLinesBehindDataEnabled()) { - mAxisRendererLeft.renderGridLines(canvas); - } - - if (mAxisRight.isDrawGridLinesBehindDataEnabled()) { - 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); - } - - int clipRestoreCount = canvas.save(); - - if (isClipDataToContentEnabled()) { - // make sure the data cannot be drawn outside the content-rect - canvas.clipRect(getViewPortHandler().getContentRect()); - } - - mRenderer.drawData(canvas); - - if (!mXAxis.isDrawGridLinesBehindDataEnabled()) { - mXAxisRenderer.renderGridLines(canvas); - } - - if (!mAxisLeft.isDrawGridLinesBehindDataEnabled()) { - mAxisRendererLeft.renderGridLines(canvas); - } - - if (!mAxisRight.isDrawGridLinesBehindDataEnabled()) { - mAxisRendererRight.renderGridLines(canvas); - } - - // if highlighting is enabled - if (valuesToHighlight()) { - mRenderer.drawHighlighted(canvas, getHighlighted()); - } - - // 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(getViewPortHandler().getContentRect()); - - mRenderer.drawValues(canvas); - - canvas.restoreToCount(clipRestoreCount); - } else { - mRenderer.drawValues(canvas); - } - - getLegendRenderer().renderLegend(canvas); - - drawDescription(canvas); - - drawMarkers(canvas); - - if (isLogEnabled()) { - 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 (isLogEnabled()) { - 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 (isLogEnabled()) { - Log.i(LOG_TAG, "Preparing... DATA NOT SET."); - } - return; - } else { - if (isLogEnabled()) { - 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 (getLegend() != null) { - getLegendRenderer().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); - - calcMinMax(); - } - - @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; - - if (getLegend() == null || !getLegend().isEnabled() || getLegend().isDrawInsideEnabled()) { - return; - } - - switch (getLegend().getOrientation()) { - case VERTICAL: - - switch (getLegend().getHorizontalAlignment()) { - case LEFT: - offsets.left += Math.min(getLegend().mNeededWidth, getViewPortHandler().getChartWidth() * getLegend().getMaxSizePercent()) + getLegend().getXOffset(); - break; - - case RIGHT: - offsets.right += Math.min(getLegend().mNeededWidth, getViewPortHandler().getChartWidth() * getLegend().getMaxSizePercent()) + getLegend().getXOffset(); - break; - - case CENTER: - - switch (getLegend().getVerticalAlignment()) { - case TOP: - offsets.top += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); - break; - - case BOTTOM: - offsets.bottom += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); - break; - - default: - break; - } - } - - break; - - case HORIZONTAL: - - switch (getLegend().getVerticalAlignment()) { - case TOP: - offsets.top += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); - - - break; - - case BOTTOM: - offsets.bottom += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); - - - break; - - default: - break; - } - break; - } - } - - private final 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.mLabelHeight + 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 = UtilsKtKt.convertDpToPixel(mMinOffset); - - getViewPortHandler().restrainViewPort(Math.max(minOffset, offsetLeft), Math.max(minOffset, offsetTop), Math.max(minOffset, offsetRight), Math.max(minOffset, offsetBottom)); - - if (isLogEnabled()) { - Log.i(LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom); - Log.i(LOG_TAG, "Content: " + getViewPortHandler().getContentRect()); - } - } - - prepareOffsetMatrix(); - prepareValuePxMatrix(); - } - - /** - * draws the grid background - */ - protected void drawGridBackground(Canvas c) { - - if (mDrawGridBackground) { - - // draw the grid background - c.drawRect(getViewPortHandler().getContentRect(), mGridBackgroundPaint); - } - - if (mDrawBorders) { - c.drawRect(getViewPortHandler().getContentRect(), mBorderPaint); - } - } - - /** - * Returns the Transformer class that contains all matrices and is - * responsible for transforming values into pixels on the screen and - * backwards. - */ - 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 = getViewPortHandler().getContentCenter(); - - getViewPortHandler().zoomIn(center.getX(), -center.getY(), mZoomMatrixBuffer); - getViewPortHandler().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 = getViewPortHandler().getContentCenter(); - - getViewPortHandler().zoomOut(center.getX(), -center.getY(), mZoomMatrixBuffer); - getViewPortHandler().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() { - - getViewPortHandler().resetZoom(mZoomMatrixBuffer); - getViewPortHandler().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 - */ - public void zoom(float scaleX, float scaleY, float x, float y) { - - getViewPortHandler().zoom(scaleX, scaleY, x, -y, mZoomMatrixBuffer); - getViewPortHandler().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 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.Companion.getInstance(getViewPortHandler(), scaleX, scaleY, xValue, yValue, getTransformer(axis), axis, this); - addViewportJob(job); - } - - /** - * Zooms to the center of the chart with the given scale factor. - */ - public void zoomToCenter(float scaleX, float scaleY) { - - MPPointF center = getCenterOffsets(); - - Matrix save = mZoomMatrixBuffer; - getViewPortHandler().zoom(scaleX, scaleY, center.getX(), -center.getY(), save); - getViewPortHandler().refresh(save, this, false); - } - - /** - * Zooms by the specified scale factor to the specified values on the specified axis. - */ - public void zoomAndCenterAnimated(float scaleX, float scaleY, float xValue, float yValue, AxisDependency axis, long duration) { - - MPPointD origin = getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentTop(), axis); - - Runnable job = AnimatedZoomJob.Companion.getInstance(getViewPortHandler(), this, getTransformer(axis), getAxis(axis), mXAxis.mAxisRange, scaleX, scaleY, getViewPortHandler().getScaleX(), getViewPortHandler().getScaleY(), xValue, yValue, (float) origin.getX(), (float) origin.getY(), duration); - addViewportJob(job); - - MPPointD.Companion.recycleInstance(origin); - } - - 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; - getViewPortHandler().fitScreen(save); - getViewPortHandler().refresh(save, this, false); - - calculateOffsets(); - postInvalidate(); - } - - /** - * Sets the minimum scale factor value to which can be zoomed out. 1f = - * fitScreen - */ - public void setScaleMinima(float scaleX, float scaleY) { - getViewPortHandler().setMinimumScaleX(scaleX); - getViewPortHandler().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); - getViewPortHandler().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); - getViewPortHandler().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 - */ - public void setVisibleXRange(float minXRange, float maxXRange) { - float minScale = mXAxis.mAxisRange / minXRange; - float maxScale = mXAxis.mAxisRange / maxXRange; - getViewPortHandler().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; - getViewPortHandler().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 axis the axis for which this limit should apply - */ - public void setVisibleYRangeMinimum(float minYRange, AxisDependency axis) { - float yScale = getAxisRange(axis) / minYRange; - getViewPortHandler().setMaximumScaleY(yScale); - } - - /** - * Limits the maximum and minimum y range that can be visible by pinching and zooming. - */ - public void setVisibleYRange(float minYRange, float maxYRange, AxisDependency axis) { - float minScale = getAxisRange(axis) / minYRange; - float maxScale = getAxisRange(axis) / maxYRange; - getViewPortHandler().setMinMaxScaleY(minScale, maxScale); - } - - - /** - * Moves the left side of the current viewport to the specified x-position. - * This also refreshes the chart by calling invalidate(). - */ - public void moveViewToX(float xValue) { - - Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), 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 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) / getViewPortHandler().getScaleY(); - - Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), 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 duration the duration of the animation in milliseconds - */ - public void moveViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) { - - MPPointD bounds = getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentTop(), axis); - - float yInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); - - Runnable job = AnimatedMoveViewJob.Companion.getInstance(getViewPortHandler(), xValue, yValue + yInView / 2f, getTransformer(axis), this, (float) bounds.getX(), (float) bounds.getY(), duration); - - addViewportJob(job); - - MPPointD.Companion.recycleInstance(bounds); - } - - /** - * Centers the viewport to the specified y value on the y-axis. - * This also refreshes the chart by calling invalidate(). - * - * @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) / getViewPortHandler().getScaleY(); - - Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), 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 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) / getViewPortHandler().getScaleY(); - float xInView = getXAxis().mAxisRange / getViewPortHandler().getScaleX(); - - Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), 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 duration the duration of the animation in milliseconds - */ - public void centerViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) { - - MPPointD bounds = getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentTop(), axis); - - float yInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); - float xInView = getXAxis().mAxisRange / getViewPortHandler().getScaleX(); - - Runnable job = AnimatedMoveViewJob.Companion.getInstance(getViewPortHandler(), xValue - xInView / 2f, yValue + yInView / 2f, getTransformer(axis), this, (float) bounds.getX(), (float) bounds.getY(), duration); - - addViewportJob(job); - - MPPointD.Companion.recycleInstance(bounds); - } - - /** - * 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(...). - */ - public void setViewPortOffsets(final float left, final float top, final float right, final float bottom) { - - mCustomViewPortEnabled = true; - post(new Runnable() { - - @Override - public void run() { - - getViewPortHandler().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(); - } - - /** - * Returns the range of the specified axis. - */ - protected float getAxisRange(AxisDependency axis) { - if (axis == AxisDependency.LEFT) { - return mAxisLeft.mAxisRange; - } else { - return mAxisRight.mAxisRange; - } - } - - /** - * Sets the OnDrawListener - */ - public void setOnDrawListener(OnDrawListener drawListener) { - this.mDrawListener = drawListener; - } - - /** - * Gets the OnDrawListener. May be null. - */ - 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. - */ - 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.Companion.getInstance(mGetPositionBuffer[0], mGetPositionBuffer[1]); - } - - /** - * sets the number of maximum visible drawn values on the chart only active - * when setDrawValues() is enabled - */ - 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 - */ - 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). - */ - 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). - */ - public void setDragEnabled(boolean enabled) { - this.mDragXEnabled = enabled; - this.mDragYEnabled = enabled; - } - - /** - * Returns true if dragging is enabled for the chart, false if not. - */ - public boolean isDragEnabled() { - return mDragXEnabled || mDragYEnabled; - } - - /** - * Set this to true to enable dragging on the X axis - */ - public void setDragXEnabled(boolean enabled) { - this.mDragXEnabled = enabled; - } - - /** - * Returns true if dragging on the X axis is enabled for the chart, false if not. - */ - public boolean isDragXEnabled() { - return mDragXEnabled; - } - - /** - * Set this to true to enable dragging on the Y axis - */ - public void setDragYEnabled(boolean enabled) { - this.mDragYEnabled = enabled; - } - - /** - * Returns true if dragging on the Y axis is enabled for the chart, false if not. - */ - 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. - */ - 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 fling gesture for the chart - */ - public void setFlingEnabled(boolean enabled) { - this.mFlingEnabled = enabled; - } - - /** - * Returns true if fling gesture is enabled for the chart, false if not. - */ - public boolean isFlingEnabled() { - return mFlingEnabled; - } - - /** - * Set this to true to enable zooming in by double-tap on the chart. - * Default: enabled - */ - public void setDoubleTapToZoomEnabled(boolean enabled) { - mDoubleTapToZoomEnabled = enabled; - } - - /** - * Returns true if zooming via double-tap is enabled false if not. - */ - public boolean isDoubleTapToZoomEnabled() { - return mDoubleTapToZoomEnabled; - } - - /** - * set this to true to draw the grid background, false if not - */ - 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. - */ - 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. - */ - public boolean isDrawBordersEnabled() { - return mDrawBorders; - } - - /** - * When enabled, the values will be clipped to contentRect, - * otherwise they can bleed outside the content rect. - */ - public void setClipValuesToContent(boolean enabled) { - mClipValuesToContent = enabled; - } - - /** - * When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can - * be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines) - * that there is unwanted clipping. - */ - public void setClipDataToContent(boolean enabled) { - mClipDataToContent = enabled; - } - - /** - * When enabled, the values will be clipped to contentRect, - * otherwise they can bleed outside the content rect. - */ - public boolean isClipValuesToContentEnabled() { - return mClipValuesToContent; - } - - /** - * When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can - * be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines) - * that there is unwanted clipping. - */ - public boolean isClipDataToContentEnabled() { - return mClipDataToContent; - } - - /** - * Sets the width of the border lines in dp. - */ - public void setBorderWidth(float width) { - mBorderPaint.setStrokeWidth(UtilsKtKt.convertDpToPixel(width)); - } - - /** - * Sets the color of the chart border lines. - */ - 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(...). - */ - public MPPointD getValuesByTouchPoint(float x, float y, AxisDependency axis) { - MPPointD result = MPPointD.Companion.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(...). - */ - 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 - */ - 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 - */ - 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.Companion.getInstance(0, 0); - - /** - * Returns the lowest x-index (value on the x-axis) that is still visible on the chart. - */ - @Override - public float getLowestVisibleX() { - getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentBottom(), posForGetLowestVisibleX); - return (float) Math.max(mXAxis.mAxisMinimum, posForGetLowestVisibleX.getX()); - } - - /** - * buffer for storing highest visible x point - */ - protected MPPointD posForGetHighestVisibleX = MPPointD.Companion.getInstance(0, 0); - - /** - * Returns the highest x-index (value on the x-axis) that is still visible - * on the chart. - */ - @Override - public float getHighestVisibleX() { - getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(getViewPortHandler().contentRight(), getViewPortHandler().contentBottom(), posForGetHighestVisibleX); - return (float) Math.min(mXAxis.mAxisMaximum, posForGetHighestVisibleX.getX()); - } - - /** - * Returns the range visible on the x-axis. - */ - public float getVisibleXRange() { - return Math.abs(getHighestVisibleX() - getLowestVisibleX()); - } - - /** - * returns the current x-scale factor - */ - public float getScaleX() { - if (getViewPortHandler() == null) { - return 1f; - } else { - return getViewPortHandler().getScaleX(); - } - } - - /** - * returns the current y-scale factor - */ - public float getScaleY() { - if (getViewPortHandler() == null) { - return 1f; - } else { - return getViewPortHandler().getScaleY(); - } - } - - /** - * if the chart is fully zoomed out, return true - */ - public boolean isFullyZoomedOut() { - return getViewPortHandler().isFullyZoomedOut(); - } - - /** - * Returns the left y-axis object. In the horizontal bar-chart, this is the - * top axis. - */ - public YAxis getAxisLeft() { - return mAxisLeft; - } - - /** - * Returns the right y-axis object. In the horizontal bar-chart, this is the - * bottom axis. - */ - public YAxis getAxisRight() { - return mAxisRight; - } - - /** - * Returns the y-axis object to the corresponding AxisDependency. In the - * horizontal bar-chart, LEFT == top, RIGHT == BOTTOM - */ - 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 - */ - public void setPinchZoom(boolean enabled) { - mPinchZoomEnabled = enabled; - } - - /** - * returns true if pinch-zoom is enabled, false if not - */ - 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. - */ - public void setDragOffsetX(float offset) { - getViewPortHandler().setDragOffsetX(offset); - } - - /** - * Set an offset in dp that allows the user to drag the chart over it's - * bounds on the y-axis. - */ - public void setDragOffsetY(float offset) { - getViewPortHandler().setDragOffsetY(offset); - } - - /** - * Returns true if both drag offsets (x and y) are zero or smaller. - */ - public boolean hasNoDragOffset() { - return getViewPortHandler().hasNoDragOffset(); - } - - public XAxisRenderer getRendererXAxis() { - return mXAxisRenderer; - } - - /** - * Sets a custom XAxisRenderer and overrides the existing (default) one. - */ - 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. - */ - 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. - */ - 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. - */ - public boolean isAnyAxisInverted() { - if (mAxisLeft.isInverted()) { - return true; - } - return mAxisRight.isInverted(); - } - - /** - * 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. - */ - public boolean isAutoScaleMinMaxEnabled() { - return mAutoScaleMinMaxEnabled; - } - - @Override - public void setPaint(Paint p, int which) { - super.setPaint(p, which); - - if (which == PAINT_GRID_BACKGROUND) { - mGridBackgroundPaint = p; - } - } - - @Override - public Paint getPaint(int which) { - Paint p = super.getPaint(which); - if (p != null) { - return p; - } - - if (which == 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] = getViewPortHandler().contentLeft(); - mOnSizeChangedBuffer[1] = getViewPortHandler().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); - getViewPortHandler().centerViewPort(mOnSizeChangedBuffer, this); - } else { - getViewPortHandler().refresh(getViewPortHandler().getMatrixTouch(), this, true); - } - } - - /** - * Sets the text color to use for the labels. Make sure to use - * getResources().getColor(...) when using a color from the resources. - */ - public void setTextColor(int color) { - mAxisRendererLeft.setTextColor(color); - mAxisRendererRight.setTextColor(color); - mXAxisRenderer.setTextColor(color); - } -} diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.kt new file mode 100644 index 000000000..a44df56ba --- /dev/null +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.kt @@ -0,0 +1,1329 @@ +package com.github.mikephil.charting.charts + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.RectF +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import com.github.mikephil.charting.components.Legend.LegendHorizontalAlignment +import com.github.mikephil.charting.components.Legend.LegendOrientation +import com.github.mikephil.charting.components.Legend.LegendVerticalAlignment +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.interfaces.dataprovider.base.BarLineScatterCandleBubbleDataProvider +import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet +import com.github.mikephil.charting.jobs.AnimatedMoveViewJob.Companion.getInstance +import com.github.mikephil.charting.jobs.AnimatedZoomJob.Companion.getInstance +import com.github.mikephil.charting.jobs.MoveViewJob.Companion.getInstance +import com.github.mikephil.charting.jobs.ZoomJob.Companion.getInstance +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.MPPointD.Companion.getInstance +import com.github.mikephil.charting.utils.MPPointD.Companion.recycleInstance +import com.github.mikephil.charting.utils.MPPointF +import com.github.mikephil.charting.utils.MPPointF.Companion.getInstance +import com.github.mikephil.charting.utils.MPPointF.Companion.recycleInstance +import com.github.mikephil.charting.utils.Transformer +import com.github.mikephil.charting.utils.convertDpToPixel +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min + +/** + * Base-class of LineChart, BarChart, ScatterChart and CandleStickChart. + */ +@Suppress("unused") +@SuppressLint("RtlHardcoded") +abstract class BarLineChartBase>> : Chart, + BarLineScatterCandleBubbleDataProvider { + /** + * the maximum number of entries to which values will be drawn + * (entry numbers greater than this value will cause value-labels to disappear) + */ + override var maxVisibleCount: Int = 100 + protected set + + /** + * Flag that indicates if auto scaling on the y axis is enabled. This is + * especially interesting for charts displaying financial data. + */ + var isAutoScaleMinMaxEnabled: Boolean = 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 + */ + var isPinchZoomEnabled: Boolean = false + protected set + + /** + * flag that indicates if double tap zoom is enabled or not + */ + var isDoubleTapToZoomEnabled: Boolean = true + + /** + * flag that indicates if highlighting per dragging over a fully zoomed out + * chart is enabled + */ + var isHighlightPerDragEnabled: Boolean = true + + /** + * if true, dragging is enabled for the chart + */ + var isDragXEnabled: Boolean = true + + /** + * Set this to true to enable dragging on the Y axis + */ + var isDragYEnabled: Boolean = true + + var isScaleXEnabled: Boolean = true + var isScaleYEnabled: Boolean = true + + /** + * if true, fling gesture is enabled for the chart + */ + var isFlingEnabled: Boolean = false + + /** + * paint object for the (by default) light grey background of the grid + */ + protected var mGridBackgroundPaint: Paint? = null + + protected var mBorderPaint: Paint? = null + + /** + * flag indicating if the grid background should be drawn or not + */ + protected var mDrawGridBackground: Boolean = false + + /** + * 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. + */ + var isDrawBordersEnabled: Boolean = false + protected set + + /** + * When enabled, the values will be clipped to contentRect, + * otherwise they can bleed outside the content rect. + */ + var isClipValuesToContentEnabled: Boolean = false + protected set + + /** + * When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can + * be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines) + * that there is unwanted clipping. + */ + var isClipDataToContentEnabled: Boolean = true + protected set + + /** + * Gets the minimum offset (padding) around the chart, defaults to 15.f + */ + /** + * Sets the minimum offset (padding) around the chart, defaults to 15.f + */ + /** + * Sets the minimum offset (padding) around the chart, defaults to 15 + */ + var minOffset: Float = 15f + + /** + * flag indicating if the chart should stay at the same position after a rotation. Default is false. + */ + var isKeepPositionOnRotation: Boolean = false + + /** + * the listener for user drawing on the chart + */ + var drawListener: OnDrawListener? = null + protected set + + /** + * the object representing the labels on the left y-axis + */ + protected var mAxisLeft: YAxis = YAxis(AxisDependency.LEFT) + + /** + * the object representing the labels on the right y-axis + */ + protected var mAxisRight: YAxis = YAxis(AxisDependency.RIGHT) + + protected var mAxisRendererLeft: YAxisRenderer + protected var mAxisRendererRight: YAxisRenderer + + protected var mLeftAxisTransformer: Transformer = Transformer(viewPortHandler) + protected var mRightAxisTransformer: Transformer = Transformer(viewPortHandler) + + protected var mXAxisRenderer: XAxisRenderer + + // /** the approximator object used for data filtering */ + // private Approximator mApproximator; + constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) + + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + + constructor(context: Context?) : super(context) + + init { + + mAxisRendererLeft = YAxisRenderer(viewPortHandler, mAxisLeft, mLeftAxisTransformer) + mAxisRendererRight = YAxisRenderer(viewPortHandler, mAxisRight, mRightAxisTransformer) + + mXAxisRenderer = XAxisRenderer(viewPortHandler, mXAxis, mLeftAxisTransformer) + + setHighlighter(ChartHighlighter(this)) + + mChartTouchListener = BarLineChartTouchListener(this, viewPortHandler.matrixTouch, 3f) + + mGridBackgroundPaint = Paint().apply { + style = Paint.Style.FILL + // setColor(Color.WHITE); + color = Color.rgb(240, 240, 240) // light + } + + // grey + mBorderPaint = Paint().apply { + style = Paint.Style.STROKE + color = Color.BLACK + strokeWidth = 1f.convertDpToPixel() + } + } + + // for performance tracking + private var totalTime: Long = 0 + private var drawCycles: Long = 0 + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + if (mData == null) { + return + } + + val startTime = System.currentTimeMillis() + + // execute all drawing commands + drawGridBackground(canvas) + + if (this.isAutoScaleMinMaxEnabled) { + 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) + } + + // Y-axis labels could have changed in size affecting the offsets + if (this.isAutoScaleMinMaxEnabled) { + calculateOffsets() + viewPortHandler.refresh(viewPortHandler.matrixTouch, this, false) + } + + mXAxisRenderer.renderAxisLine(canvas) + mAxisRendererLeft.renderAxisLine(canvas) + mAxisRendererRight.renderAxisLine(canvas) + + if (mXAxis.isDrawGridLinesBehindDataEnabled) { + mXAxisRenderer.renderGridLines(canvas) + } + + if (mAxisLeft.isDrawGridLinesBehindDataEnabled) { + mAxisRendererLeft.renderGridLines(canvas) + } + + if (mAxisRight.isDrawGridLinesBehindDataEnabled) { + 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) + } + + var clipRestoreCount = canvas.save() + + if (this.isClipDataToContentEnabled) { + // make sure the data cannot be drawn outside the content-rect + canvas.clipRect(viewPortHandler.contentRect) + } + + mRenderer!!.drawData(canvas) + + if (!mXAxis.isDrawGridLinesBehindDataEnabled) { + mXAxisRenderer.renderGridLines(canvas) + } + + if (!mAxisLeft.isDrawGridLinesBehindDataEnabled) { + mAxisRendererLeft.renderGridLines(canvas) + } + + if (!mAxisRight.isDrawGridLinesBehindDataEnabled) { + mAxisRendererRight.renderGridLines(canvas) + } + + // if highlighting is enabled + if (valuesToHighlight()) { + mRenderer!!.drawHighlighted(canvas, highlighted!!) + } + + // 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 (this.isClipValuesToContentEnabled) { + clipRestoreCount = canvas.save() + canvas.clipRect(viewPortHandler.contentRect) + + mRenderer!!.drawValues(canvas) + + canvas.restoreToCount(clipRestoreCount) + } else { + mRenderer!!.drawValues(canvas) + } + + legendRenderer!!.renderLegend(canvas) + + drawDescription(canvas) + + drawMarkers(canvas) + + if (isLogEnabled) { + val drawtime = (System.currentTimeMillis() - startTime) + totalTime += drawtime + drawCycles += 1 + val average = totalTime / drawCycles + Log.i(LOG_TAG, "Drawtime: $drawtime ms, average: $average ms, cycles: $drawCycles") + } + } + + /** + * RESET PERFORMANCE TRACKING FIELDS + */ + fun resetTracking() { + totalTime = 0 + drawCycles = 0 + } + + protected open fun prepareValuePxMatrix() { + if (isLogEnabled) { + 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, this.mAxisRight.mAxisMinimum) + mLeftAxisTransformer.prepareMatrixValuePx(mXAxis.mAxisMinimum, mXAxis.mAxisRange, mAxisLeft.mAxisRange, mAxisLeft.mAxisMinimum) + } + + protected fun prepareOffsetMatrix() { + mRightAxisTransformer.prepareMatrixOffset(mAxisRight.isInverted) + mLeftAxisTransformer.prepareMatrixOffset(mAxisLeft.isInverted) + } + + override fun notifyDataSetChanged() { + if (mData == null) { + if (isLogEnabled) { + Log.i(LOG_TAG, "Preparing... DATA NOT SET.") + } + return + } else { + if (isLogEnabled) { + 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 (legend != null) { + legendRenderer!!.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 fun autoScale() { + val fromX = lowestVisibleX + val toX = highestVisibleX + + mData!!.calcMinMaxY(fromX, toX) + + calcMinMax() + } + + override fun calcMinMax() { + mXAxis.calculate(mData!!.xMin, mData!!.xMax) + + // 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 open fun calculateLegendOffsets(offsets: RectF) { + offsets.left = 0f + offsets.right = 0f + offsets.top = 0f + offsets.bottom = 0f + + if (legend == null || !legend!!.isEnabled || legend!!.isDrawInsideEnabled) { + return + } + + when (legend!!.orientation) { + LegendOrientation.VERTICAL -> when (legend!!.horizontalAlignment) { + LegendHorizontalAlignment.LEFT -> offsets.left += min( + legend!!.mNeededWidth, + viewPortHandler.chartWidth * legend!!.maxSizePercent + ) + legend!!.xOffset + + LegendHorizontalAlignment.RIGHT -> offsets.right += min( + legend!!.mNeededWidth, + viewPortHandler.chartWidth * legend!!.maxSizePercent + ) + legend!!.xOffset + + LegendHorizontalAlignment.CENTER -> when (legend!!.verticalAlignment) { + LegendVerticalAlignment.TOP -> offsets.top += min( + legend!!.mNeededHeight, + viewPortHandler.chartHeight * legend!!.maxSizePercent + ) + legend!!.yOffset + + LegendVerticalAlignment.BOTTOM -> offsets.bottom += min( + legend!!.mNeededHeight, + viewPortHandler.chartHeight * legend!!.maxSizePercent + ) + legend!!.yOffset + + else -> {} + } + } + + LegendOrientation.HORIZONTAL -> when (legend!!.verticalAlignment) { + LegendVerticalAlignment.TOP -> offsets.top += min( + legend!!.mNeededHeight, + viewPortHandler.chartHeight * legend!!.maxSizePercent + ) + legend!!.yOffset + + + LegendVerticalAlignment.BOTTOM -> offsets.bottom += min( + legend!!.mNeededHeight, + viewPortHandler.chartHeight * legend!!.maxSizePercent + ) + legend!!.yOffset + + + else -> {} + } + } + } + + private val mOffsetsBuffer = RectF() + + public override fun calculateOffsets() { + if (!mCustomViewPortEnabled) { + var offsetLeft = 0f + var offsetRight = 0f + var offsetTop = 0f + var 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.paintAxisLabels) + } + + if (mAxisRight.needsOffset()) { + offsetRight += mAxisRight.getRequiredWidthSpace(mAxisRendererRight.paintAxisLabels) + } + + if (mXAxis.isEnabled && mXAxis.isDrawLabelsEnabled) { + val xLabelHeight = mXAxis.mLabelHeight + mXAxis.yOffset + + // offsets for x-labels + when (mXAxis.position) { + XAxisPosition.BOTTOM -> { + offsetBottom += xLabelHeight + } + XAxisPosition.TOP -> { + offsetTop += xLabelHeight + } + XAxisPosition.BOTH_SIDED -> { + offsetBottom += xLabelHeight + offsetTop += xLabelHeight + } + + XAxisPosition.TOP_INSIDE -> TODO() + XAxisPosition.BOTTOM_INSIDE -> TODO() + null -> Log.e(LOG_TAG, "calculateOffsets(): Cannot calculate offset for XAxisPosition.TOP_INSIDE or BOTTOM_INSIDE") + } + } + + offsetTop += extraTopOffset + offsetRight += extraRightOffset + offsetBottom += extraBottomOffset + offsetLeft += extraLeftOffset + + val minOffset = minOffset.convertDpToPixel() + + viewPortHandler.restrainViewPort(max(minOffset, offsetLeft), max(minOffset, offsetTop), max(minOffset, offsetRight), max(minOffset, offsetBottom)) + + if (isLogEnabled) { + Log.i(LOG_TAG, "offsetLeft: $offsetLeft, offsetTop: $offsetTop, offsetRight: $offsetRight, offsetBottom: $offsetBottom") + Log.i(LOG_TAG, "Content: " + viewPortHandler.contentRect) + } + } + + prepareOffsetMatrix() + prepareValuePxMatrix() + } + + /** + * draws the grid background + */ + protected fun drawGridBackground(c: Canvas) { + if (mDrawGridBackground) { + // draw the grid background + + c.drawRect(viewPortHandler.contentRect, mGridBackgroundPaint!!) + } + + if (this.isDrawBordersEnabled) { + c.drawRect(viewPortHandler.contentRect, mBorderPaint!!) + } + } + + /** + * Returns the Transformer class that contains all matrices and is + * responsible for transforming values into pixels on the screen and + * backwards. + */ + override fun getTransformer(axis: AxisDependency?): Transformer { + return if (axis == AxisDependency.LEFT) { + mLeftAxisTransformer + } else { + mRightAxisTransformer + } + } + + override fun onTouchEvent(event: MotionEvent?): Boolean { + super.onTouchEvent(event) + + if (mChartTouchListener == null || mData == null) { + return false + } + + // check if touch gestures are enabled + return if (!mTouchEnabled) { + false + } else { + mChartTouchListener!!.onTouch(this, event) + } + } + + override fun computeScroll() { + if (mChartTouchListener is BarLineChartTouchListener) { + (mChartTouchListener as BarLineChartTouchListener).computeScroll() + } + } + + /** + * CODE BELOW THIS RELATED TO SCALING AND GESTURES AND MODIFICATION OF THE + * VIEWPORT + */ + protected var mZoomMatrixBuffer: Matrix = Matrix() + + /** + * Zooms in by 1.4f, into the charts center. + */ + fun zoomIn() { + val center = viewPortHandler.contentCenter + + viewPortHandler.zoomIn(center.x, -center.y, mZoomMatrixBuffer) + viewPortHandler.refresh(mZoomMatrixBuffer, this, false) + + 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. + */ + fun zoomOut() { + val center = viewPortHandler.contentCenter + + viewPortHandler.zoomOut(center.x, -center.y, mZoomMatrixBuffer) + viewPortHandler.refresh(mZoomMatrixBuffer, this, false) + + 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. + */ + fun resetZoom() { + viewPortHandler.resetZoom(mZoomMatrixBuffer) + viewPortHandler.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 + */ + fun zoom(scaleX: Float, scaleY: Float, x: Float, y: Float) { + viewPortHandler.zoom(scaleX, scaleY, x, -y, mZoomMatrixBuffer) + viewPortHandler.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 axis the axis relative to which the zoom should take place + */ + fun zoom(scaleX: Float, scaleY: Float, xValue: Float, yValue: Float, axis: AxisDependency?) { + val job: Runnable = getInstance(viewPortHandler, scaleX, scaleY, xValue, yValue, getTransformer(axis), axis, this) + addViewportJob(job) + } + + /** + * Zooms to the center of the chart with the given scale factor. + */ + fun zoomToCenter(scaleX: Float, scaleY: Float) { + val center = centerOffsets + + val save = mZoomMatrixBuffer + viewPortHandler.zoom(scaleX, scaleY, center.x, -center.y, save) + viewPortHandler.refresh(save, this, false) + } + + /** + * Zooms by the specified scale factor to the specified values on the specified axis. + */ + fun zoomAndCenterAnimated(scaleX: Float, scaleY: Float, xValue: Float, yValue: Float, axis: AxisDependency?, duration: Long) { + val origin = getValuesByTouchPoint(viewPortHandler.contentLeft(), viewPortHandler.contentTop(), axis) + + val job: Runnable = getInstance( + viewPortHandler, + this, + getTransformer(axis), + getAxis(axis), + mXAxis.mAxisRange, + scaleX, + scaleY, + viewPortHandler.scaleX, + viewPortHandler.scaleY, + xValue, + yValue, + origin.x.toFloat(), + origin.y.toFloat(), + duration + ) + addViewportJob(job) + + recycleInstance(origin) + } + + protected var mFitScreenMatrixBuffer: Matrix = Matrix() + + /** + * Resets all zooming and dragging and makes the chart fit exactly it's + * bounds. + */ + fun fitScreen() { + val save = mFitScreenMatrixBuffer + viewPortHandler.fitScreen(save) + viewPortHandler.refresh(save, this, false) + + calculateOffsets() + postInvalidate() + } + + /** + * Sets the minimum scale factor value to which can be zoomed out. 1f = + * fitScreen + */ + fun setScaleMinima(scaleX: Float, scaleY: Float) { + viewPortHandler.setMinimumScaleX(scaleX) + viewPortHandler.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. + */ + open fun setVisibleXRangeMaximum(maxXRange: Float) { + val xScale = mXAxis.mAxisRange / (maxXRange) + viewPortHandler.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. + */ + open fun setVisibleXRangeMinimum(minXRange: Float) { + val xScale = mXAxis.mAxisRange / (minXRange) + viewPortHandler.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 + */ + open fun setVisibleXRange(minXRange: Float, maxXRange: Float) { + val minScale = mXAxis.mAxisRange / minXRange + val maxScale = mXAxis.mAxisRange / maxXRange + viewPortHandler.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 + */ + open fun setVisibleYRangeMaximum(maxYRange: Float, axis: AxisDependency?) { + val yScale = getAxisRange(axis) / maxYRange + viewPortHandler.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 axis the axis for which this limit should apply + */ + open fun setVisibleYRangeMinimum(minYRange: Float, axis: AxisDependency?) { + val yScale = getAxisRange(axis) / minYRange + viewPortHandler.setMaximumScaleY(yScale) + } + + /** + * Limits the maximum and minimum y range that can be visible by pinching and zooming. + */ + open fun setVisibleYRange(minYRange: Float, maxYRange: Float, axis: AxisDependency?) { + val minScale = getAxisRange(axis) / minYRange + val maxScale = getAxisRange(axis) / maxYRange + viewPortHandler.setMinMaxScaleY(minScale, maxScale) + } + + + /** + * Moves the left side of the current viewport to the specified x-position. + * This also refreshes the chart by calling invalidate(). + */ + fun moveViewToX(xValue: Float) { + val job: Runnable = getInstance(viewPortHandler, 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 axis - which axis should be used as a reference for the y-axis + */ + fun moveViewTo(xValue: Float, yValue: Float, axis: AxisDependency?) { + val yInView = getAxisRange(axis) / viewPortHandler.scaleY + + val job: Runnable = getInstance(viewPortHandler, 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 duration the duration of the animation in milliseconds + */ + fun moveViewToAnimated(xValue: Float, yValue: Float, axis: AxisDependency?, duration: Long) { + val bounds = getValuesByTouchPoint(viewPortHandler.contentLeft(), viewPortHandler.contentTop(), axis) + + val yInView = getAxisRange(axis) / viewPortHandler.scaleY + + val job: Runnable = + getInstance(viewPortHandler, xValue, yValue + yInView / 2f, getTransformer(axis), this, bounds.x.toFloat(), bounds.y.toFloat(), duration) + + addViewportJob(job) + + recycleInstance(bounds) + } + + /** + * Centers the viewport to the specified y value on the y-axis. + * This also refreshes the chart by calling invalidate(). + * + * @param axis - which axis should be used as a reference for the y-axis + */ + fun centerViewToY(yValue: Float, axis: AxisDependency?) { + val valsInView = getAxisRange(axis) / viewPortHandler.scaleY + + val job: Runnable = getInstance(viewPortHandler, 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 axis - which axis should be used as a reference for the y axis + */ + fun centerViewTo(xValue: Float, yValue: Float, axis: AxisDependency?) { + val yInView = getAxisRange(axis) / viewPortHandler.scaleY + val xInView = xAxis.mAxisRange / viewPortHandler.scaleX + + val job: Runnable = getInstance(viewPortHandler, 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 duration the duration of the animation in milliseconds + */ + fun centerViewToAnimated(xValue: Float, yValue: Float, axis: AxisDependency?, duration: Long) { + val bounds = getValuesByTouchPoint(viewPortHandler.contentLeft(), viewPortHandler.contentTop(), axis) + + val yInView = getAxisRange(axis) / viewPortHandler.scaleY + val xInView = xAxis.mAxisRange / viewPortHandler.scaleX + + val job: Runnable = getInstance( + viewPortHandler, + xValue - xInView / 2f, + yValue + yInView / 2f, + getTransformer(axis), + this, + bounds.x.toFloat(), + bounds.y.toFloat(), + duration + ) + + addViewportJob(job) + + recycleInstance(bounds) + } + + /** + * flag that indicates if a custom viewport offset has been set + */ + private var 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(...). + */ + fun setViewPortOffsets(left: Float, top: Float, right: Float, bottom: Float) { + mCustomViewPortEnabled = true + post { + viewPortHandler.restrainViewPort(left, top, right, bottom) + prepareOffsetMatrix() + prepareValuePxMatrix() + } + } + + /** + * Resets all custom offsets set via setViewPortOffsets(...) method. Allows + * the chart to again calculate all offsets automatically. + */ + fun resetViewPortOffsets() { + mCustomViewPortEnabled = false + calculateOffsets() + } + + /** + * Returns the range of the specified axis. + */ + protected fun getAxisRange(axis: AxisDependency?): Float { + return if (axis == AxisDependency.LEFT) { + mAxisLeft.mAxisRange + } else { + mAxisRight.mAxisRange + } + } + + /** + * Sets the OnDrawListener + */ + fun setOnDrawListener(drawListener: OnDrawListener?) { + this.drawListener = drawListener + } + + protected var mGetPositionBuffer: FloatArray = FloatArray(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. + */ + open fun getPosition(e: Entry?, axis: AxisDependency?): MPPointF? { + if (e == null) { + return null + } + + mGetPositionBuffer[0] = e.x + mGetPositionBuffer[1] = e.y + + getTransformer(axis).pointValuesToPixel(mGetPositionBuffer) + + return getInstance(mGetPositionBuffer[0], mGetPositionBuffer[1]) + } + + /** + * sets the number of maximum visible drawn values on the chart only active + * when setDrawValues() is enabled + */ + fun setMaxVisibleValueCount(count: Int) { + this.maxVisibleCount = count + } + + /** + * Sets the color for the background of the chart-drawing area (everything + * behind the grid lines). + */ + fun setGridBackgroundColor(color: Int) { + mGridBackgroundPaint!!.color = color + } + + var isDragEnabled: Boolean + /** + * Returns true if dragging is enabled for the chart, false if not. + */ + get() = this.isDragXEnabled || this.isDragYEnabled + /** + * Set this to true to enable dragging (moving the chart with the finger) + * for the chart (this does not effect scaling). + */ + set(enabled) { + this.isDragXEnabled = enabled + this.isDragYEnabled = enabled + } + + /** + * 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. + */ + fun setScaleEnabled(enabled: Boolean) { + this.isScaleXEnabled = enabled + this.isScaleYEnabled = enabled + } + + /** + * set this to true to draw the grid background, false if not + */ + fun setDrawGridBackground(enabled: Boolean) { + 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. + */ + fun setDrawBorders(enabled: Boolean) { + this.isDrawBordersEnabled = enabled + } + + /** + * When enabled, the values will be clipped to contentRect, + * otherwise they can bleed outside the content rect. + */ + fun setClipValuesToContent(enabled: Boolean) { + this.isClipValuesToContentEnabled = enabled + } + + /** + * When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can + * be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines) + * that there is unwanted clipping. + */ + fun setClipDataToContent(enabled: Boolean) { + this.isClipDataToContentEnabled = enabled + } + + /** + * Sets the width of the border lines in dp. + */ + fun setBorderWidth(width: Float) { + mBorderPaint!!.strokeWidth = width.convertDpToPixel() + } + + /** + * Sets the color of the chart border lines. + */ + fun setBorderColor(color: Int) { + mBorderPaint!!.color = color + } + + /** + * 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(...). + */ + fun getValuesByTouchPoint(x: Float, y: Float, axis: AxisDependency?): MPPointD { + val result = getInstance(0.0, 0.0) + getValuesByTouchPoint(x, y, axis, result) + return result + } + + fun getValuesByTouchPoint(x: Float, y: Float, axis: AxisDependency?, outputPoint: MPPointD) { + 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(...). + */ + fun getPixelForValues(x: Float, y: Float, axis: AxisDependency?): MPPointD { + return getTransformer(axis).getPixelForValues(x, y) + } + + /** + * returns the Entry object displayed at the touched position of the chart + */ + fun getEntryByTouchPoint(x: Float, y: Float): Entry? { + val 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 + */ + fun getDataSetByTouchPoint(x: Float, y: Float): IBarLineScatterCandleBubbleDataSet<*>? { + val h = getHighlightByTouchPoint(x, y) + if (h != null) { + return mData!!.getDataSetByIndex(h.dataSetIndex) + } + return null + } + + /** + * buffer for storing lowest visible x point + */ + protected var posForGetLowestVisibleX: MPPointD = getInstance(0.0, 0.0) + + override val lowestVisibleX: Float + /** + * Returns the lowest x-index (value on the x-axis) that is still visible on the chart. + */ + get() { + getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(viewPortHandler.contentLeft(), viewPortHandler.contentBottom(), posForGetLowestVisibleX) + return max(mXAxis.mAxisMinimum.toDouble(), posForGetLowestVisibleX.x).toFloat() + } + + /** + * buffer for storing highest visible x point + */ + protected var posForGetHighestVisibleX: MPPointD = getInstance(0.0, 0.0) + + override val highestVisibleX: Float + /** + * Returns the highest x-index (value on the x-axis) that is still visible + * on the chart. + */ + get() { + getTransformer(AxisDependency.LEFT).getValuesByTouchPoint( + viewPortHandler.contentRight(), + viewPortHandler.contentBottom(), + posForGetHighestVisibleX + ) + return min(mXAxis.mAxisMaximum.toDouble(), posForGetHighestVisibleX.x).toFloat() + } + + val visibleXRange: Float + /** + * Returns the range visible on the x-axis. + */ + get() = abs(highestVisibleX - lowestVisibleX) + + /** + * returns the current x-scale factor + */ + override fun getScaleX(): Float { + return viewPortHandler.scaleX + } + + /** + * returns the current y-scale factor + */ + override fun getScaleY(): Float { + return viewPortHandler.scaleY + } + + val isFullyZoomedOut: Boolean + /** + * if the chart is fully zoomed out, return true + */ + get() = viewPortHandler.isFullyZoomedOut + + val axisLeft: YAxis + /** + * Returns the left y-axis object. In the horizontal bar-chart, this is the + * top axis. + */ + get() = mAxisLeft + + val axisRight: YAxis + /** + * Returns the right y-axis object. In the horizontal bar-chart, this is the + * bottom axis. + */ + get() = mAxisRight + + /** + * Returns the y-axis object to the corresponding AxisDependency. In the + * horizontal bar-chart, LEFT == top, RIGHT == BOTTOM + */ + fun getAxis(axis: AxisDependency?): YAxis { + return if (axis == AxisDependency.LEFT) { + mAxisLeft + } else { + mAxisRight + } + } + + override fun isInverted(axis: AxisDependency?): Boolean { + 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 + */ + fun setPinchZoom(enabled: Boolean) { + this.isPinchZoomEnabled = enabled + } + + /** + * Set an offset in dp that allows the user to drag the chart over it's + * bounds on the x-axis. + */ + fun setDragOffsetX(offset: Float) { + viewPortHandler.setDragOffsetX(offset) + } + + /** + * Set an offset in dp that allows the user to drag the chart over it's + * bounds on the y-axis. + */ + fun setDragOffsetY(offset: Float) { + viewPortHandler.setDragOffsetY(offset) + } + + /** + * Returns true if both drag offsets (x and y) are zero or smaller. + */ + fun hasNoDragOffset(): Boolean { + return viewPortHandler.hasNoDragOffset() + } + + val rendererXAxis: XAxisRenderer + get() = mXAxisRenderer + + /** + * Sets a custom XAxisRenderer and overrides the existing (default) one. + */ + fun setXAxisRenderer(xAxisRenderer: XAxisRenderer) { + mXAxisRenderer = xAxisRenderer + } + + var rendererLeftYAxis: YAxisRenderer + get() = mAxisRendererLeft + /** + * Sets a custom axis renderer for the left axis and overwrites the existing one. + */ + set(rendererLeftYAxis) { + mAxisRendererLeft = rendererLeftYAxis + } + + var rendererRightYAxis: YAxisRenderer + get() = mAxisRendererRight + /** + * Sets a custom axis renderer for the right axis and overwrites the existing one. + */ + set(rendererRightYAxis) { + mAxisRendererRight = rendererRightYAxis + } + + override val yChartMax: Float + get() = max(mAxisLeft.mAxisMaximum, mAxisRight.mAxisMaximum) + + override val yChartMin: Float + get() = min(mAxisLeft.mAxisMinimum, mAxisRight.mAxisMinimum) + + val isAnyAxisInverted: Boolean + /** + * Returns true if either the left or the right or both axes are inverted. + */ + get() { + if (mAxisLeft.isInverted) { + return true + } + return mAxisRight.isInverted + } + + override fun setPaint(p: Paint, which: Int) { + super.setPaint(p, which) + + if (which == PAINT_GRID_BACKGROUND) { + mGridBackgroundPaint = p + } + } + + override fun getPaint(which: Int): Paint? { + val p = super.getPaint(which) + if (p != null) { + return p + } + + if (which == PAINT_GRID_BACKGROUND) { + return mGridBackgroundPaint + } + + return null + } + + protected var mOnSizeChangedBuffer: FloatArray = FloatArray(2) + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + // Saving current position of chart. + + mOnSizeChangedBuffer[1] = 0f + mOnSizeChangedBuffer[0] = mOnSizeChangedBuffer[1] + + if (this.isKeepPositionOnRotation) { + mOnSizeChangedBuffer[0] = viewPortHandler.contentLeft() + mOnSizeChangedBuffer[1] = viewPortHandler.contentTop() + getTransformer(AxisDependency.LEFT).pixelsToValue(mOnSizeChangedBuffer) + } + + //Superclass transforms chart. + super.onSizeChanged(w, h, oldw, oldh) + + if (this.isKeepPositionOnRotation) { + //Restoring old position of chart. + + getTransformer(AxisDependency.LEFT).pointValuesToPixel(mOnSizeChangedBuffer) + viewPortHandler.centerViewPort(mOnSizeChangedBuffer, this) + } else { + viewPortHandler.refresh(viewPortHandler.matrixTouch, this, true) + } + } + + /** + * Sets the text color to use for the labels. Make sure to use + * getResources().getColor(...) when using a color from the resources. + */ + fun setTextColor(color: Int) { + mAxisRendererLeft.setTextColor(color) + mAxisRendererRight.setTextColor(color) + mXAxisRenderer.setTextColor(color) + } +} diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BubbleChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BubbleChart.kt index e20e810f5..a668226e7 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BubbleChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BubbleChart.kt @@ -12,7 +12,7 @@ import com.github.mikephil.charting.renderer.BubbleChartRenderer * is the area of the bubble, not the radius or diameter of the bubble that * conveys the data. */ -class BubbleChart : BarLineChartBase, BubbleDataProvider { +class BubbleChart : BarLineChartBase, BubbleDataProvider { constructor(context: Context?) : super(context) constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CandleStickChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CandleStickChart.kt index 1ffc56251..5900aaf11 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CandleStickChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CandleStickChart.kt @@ -3,14 +3,13 @@ package com.github.mikephil.charting.charts import android.content.Context import android.util.AttributeSet import com.github.mikephil.charting.data.CandleData -import com.github.mikephil.charting.data.ChartData import com.github.mikephil.charting.interfaces.dataprovider.CandleDataProvider import com.github.mikephil.charting.renderer.CandleStickChartRenderer /** * Financial chart type that draws candle-sticks (OHCL chart). */ -class CandleStickChart : BarLineChartBase, CandleDataProvider { +class CandleStickChart : BarLineChartBase, CandleDataProvider { constructor(context: Context?) : super(context) constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/HorizontalBarChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/HorizontalBarChart.kt index a32375f81..06bda1a85 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/HorizontalBarChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/HorizontalBarChart.kt @@ -35,11 +35,9 @@ open class HorizontalBarChart : BarChart { constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) - override fun init() { + init { viewPortHandler = HorizontalViewPortHandler() - super.init() - mLeftAxisTransformer = TransformerHorizontalBarChart(viewPortHandler) mRightAxisTransformer = TransformerHorizontalBarChart(viewPortHandler) @@ -174,7 +172,7 @@ open class HorizontalBarChart : BarChart { offsetBottom += extraBottomOffset offsetLeft += extraLeftOffset - val minOffset = mMinOffset.convertDpToPixel() + val minOffset = minOffset.convertDpToPixel() viewPortHandler.restrainViewPort( max(minOffset, offsetLeft), @@ -226,7 +224,7 @@ open class HorizontalBarChart : BarChart { outputRect.set(left, top, right, bottom) - getTransformer(set!!.axisDependency)!!.rectValueToPixel(outputRect) + getTransformer(set!!.axisDependency).rectValueToPixel(outputRect) } } @@ -244,7 +242,7 @@ open class HorizontalBarChart : BarChart { vals[0] = e.y vals[1] = e.x - getTransformer(axis)!!.pointValuesToPixel(vals) + getTransformer(axis).pointValuesToPixel(vals) return getInstance(vals[0], vals[1]) } @@ -266,7 +264,7 @@ open class HorizontalBarChart : BarChart { override val lowestVisibleX: Float get() { - getTransformer(AxisDependency.LEFT)!!.getValuesByTouchPoint( + getTransformer(AxisDependency.LEFT).getValuesByTouchPoint( viewPortHandler.contentLeft(), viewPortHandler.contentBottom(), posForGetLowestVisibleX ) @@ -275,7 +273,7 @@ open class HorizontalBarChart : BarChart { override val highestVisibleX: Float get() { - getTransformer(AxisDependency.LEFT)!!.getValuesByTouchPoint( + getTransformer(AxisDependency.LEFT).getValuesByTouchPoint( viewPortHandler.contentLeft(), viewPortHandler.contentTop(), posForGetHighestVisibleX ) diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/LineDataProvider.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/LineDataProvider.kt index bd44ade84..336178cdd 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/LineDataProvider.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/LineDataProvider.kt @@ -1,11 +1,8 @@ package com.github.mikephil.charting.interfaces.dataprovider -import com.github.mikephil.charting.components.YAxis -import com.github.mikephil.charting.components.YAxis.AxisDependency import com.github.mikephil.charting.data.LineData import com.github.mikephil.charting.interfaces.dataprovider.base.BarLineScatterCandleBubbleDataProvider interface LineDataProvider : BarLineScatterCandleBubbleDataProvider { val lineData: LineData? - fun getAxis(dependency: AxisDependency): YAxis? } \ No newline at end of file diff --git a/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt index 1333332d1..af719016a 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt @@ -45,7 +45,7 @@ class BubbleChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSel binding.chart1.setTouchEnabled(true) // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) binding.chart1.setMaxVisibleValueCount(200) diff --git a/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt index 293e754b9..329e1b480 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt @@ -42,7 +42,7 @@ class CubicLineChartActivity : DemoBase(), OnSeekBarChangeListener { binding.chart1.setTouchEnabled(true) // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) // if disabled, scaling can be done on x- and y-axis separately diff --git a/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt index f7045957a..92c605e5e 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt @@ -46,7 +46,7 @@ class InvertedLineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartVa binding.chart1.setTouchEnabled(true) // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) // if disabled, scaling can be done on x- and y-axis separately diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt index 65296b71e..426d52a95 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt @@ -61,7 +61,7 @@ class LineChartActivityColored : DemoBase() { chart.setTouchEnabled(true) // enable scaling and dragging - chart.setDragEnabled(true) + chart.isDragEnabled = true chart.setScaleEnabled(true) // if disabled, scaling can be done on x- and y-axis separately diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt index 2bba877ab..7763868a7 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt @@ -55,7 +55,7 @@ class LineChartDualAxisActivity : DemoBase(), OnSeekBarChangeListener, OnChartVa binding.chart1.dragDecelerationFrictionCoef = 0.9f // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) binding.chart1.setDrawGridBackground(false) binding.chart1.isHighlightPerDragEnabled = true diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt index 19905fe0f..d5f7914fe 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt @@ -49,7 +49,7 @@ class LineChartTimeActivity : DemoBase(), OnSeekBarChangeListener { binding.chart1.dragDecelerationFrictionCoef = 0.9f // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) binding.chart1.setDrawGridBackground(false) binding.chart1.isHighlightPerDragEnabled = true diff --git a/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt index d7035668e..97d244d23 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt @@ -52,7 +52,7 @@ class MultiLineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartGestu binding.chart1.setTouchEnabled(true) // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) // if disabled, scaling can be done on x- and y-axis separately diff --git a/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt b/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt index 0d7e85da0..62d8e338d 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt @@ -35,7 +35,7 @@ class PerformanceLineChart : DemoBase(), OnSeekBarChangeListener { binding.chart1.setTouchEnabled(true) // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) // if disabled, scaling can be done on x- and y-axis separately diff --git a/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt index 1ee76c327..11a848ccd 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt @@ -40,7 +40,7 @@ class RealtimeLineChartActivity : DemoBase(), OnChartValueSelectedListener { binding.chart1.setTouchEnabled(true) // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) binding.chart1.setDrawGridBackground(false) diff --git a/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt index 7e7605a60..f15fa603b 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt @@ -44,7 +44,7 @@ class ScatterChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSe binding.chart1.maxHighlightDistance = 50f // enable scaling and dragging - binding.chart1.setDragEnabled(true) + binding.chart1.isDragEnabled = true binding.chart1.setScaleEnabled(true) binding.chart1.setMaxVisibleValueCount(200)