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 189fddbde..14815cac7 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 @@ -68,10 +68,10 @@ open class BarChart : BarLineChartBase, BarDataProvider { constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) - protected override fun init() { + override fun init() { super.init() - mRenderer = BarChartRenderer(this, mAnimator, mViewPortHandler, mDrawRoundedBars, mRoundedBarRadius) + mRenderer = BarChartRenderer(this, mAnimator, viewPortHandler, mDrawRoundedBars, mRoundedBarRadius) setHighlighter(BarHighlighter(this)) @@ -79,7 +79,7 @@ open class BarChart : BarLineChartBase, BarDataProvider { xAxis.spaceMax = 0.5f } - protected override fun calcMinMax() { + override fun calcMinMax() { mData?.let { barData -> if (mFitBars) { mXAxis.calculate(barData.xMin - barData.barWidth / 2f, barData.xMax + barData.barWidth / 2f) @@ -108,18 +108,49 @@ open class BarChart : BarLineChartBase, BarDataProvider { Log.e(LOG_TAG, "Can't select by touch. No data set.") return null } else { - val h = highlighter.getHighlight(x, y) - if (h == null || !isHighlightFullBarEnabled) return h - - // For isHighlightFullBarEnabled, remove stackIndex - return Highlight( - h.x, h.y, - h.xPx, h.yPx, - h.dataSetIndex, -1, h.axis - ) + highlighter?.let { + val h = it.getHighlight(x, y) + if (h == null || !isHighlightFullBarEnabled) return h + + // For isHighlightFullBarEnabled, remove stackIndex + return Highlight( + h.x, h.y, + h.xPx, h.yPx, + h.dataSetIndex, -1, h.axis + ) + } } + return null } + override val accessibilityDescription: String + get() { + barData?.let { barData -> + val entryCount = barData.entryCount + + // Find the min and max index + val yAxisValueFormatter = axisLeft.valueFormatter + val minVal = yAxisValueFormatter!!.getFormattedValue(barData.yMin, null) + val maxVal = yAxisValueFormatter.getFormattedValue(barData.yMax, null) + + // Data range... + val xAxisValueFormatter = xAxis.valueFormatter + val minRange = xAxisValueFormatter!!.getFormattedValue(barData.xMin, null) + val maxRange = xAxisValueFormatter.getFormattedValue(barData.xMax, null) + + val entries = if (entryCount == 1) "entry" else "entries" + + // Format the values of min and max; to recite them back + return String.format( + Locale.getDefault(), "The bar chart has %d %s. " + + "The minimum value is %s and maximum value is %s." + + "Data ranges from %s to %s.", + entryCount, entries, minVal, maxVal, minRange, maxRange + ) + } + return "" + } + /** * Returns the bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be * found in the charts data. Performance-intensive code should use void getBarBounds(BarEntry, RectF) instead. @@ -180,10 +211,10 @@ open class BarChart : BarLineChartBase, BarDataProvider { /** * Highlights the value at the given x-value in the given DataSet. Provide * -1 as the dataSetIndex to undo all highlighting. - * @param stackIndex the index inside the stack - only relevant for stacked entries + * @param dataIndex the index inside the stack - only relevant for stacked entries */ - override fun highlightValue(x: Float, dataSetIndex: Int, stackIndex: Int) { - highlightValue(Highlight(x, dataSetIndex, stackIndex), false) + override fun getHighlightValue(x: Float, dataSetIndex: Int, dataIndex: Int) { + highlightValue(Highlight(x, dataSetIndex, dataIndex), false) } override val barData: BarData? @@ -225,34 +256,8 @@ open class BarChart : BarLineChartBase, BarDataProvider { init() } - override fun getAccessibilityDescription(): String { - barData?.let { barData -> - val entryCount = barData.entryCount - - // Find the min and max index - val yAxisValueFormatter = axisLeft.valueFormatter - val minVal = yAxisValueFormatter!!.getFormattedValue(barData.yMin, null) - val maxVal = yAxisValueFormatter.getFormattedValue(barData.yMax, null) - - // Data range... - val xAxisValueFormatter = xAxis.valueFormatter - val minRange = xAxisValueFormatter!!.getFormattedValue(barData.xMin, null) - val maxRange = xAxisValueFormatter.getFormattedValue(barData.xMax, null) - - val entries = if (entryCount == 1) "entry" else "entries" - - // Format the values of min and max; to recite them back - return String.format( - Locale.getDefault(), "The bar chart has %d %s. " + - "The minimum value is %s and maximum value is %s." + - "Data ranges from %s to %s.", - entryCount, entries, minVal, maxVal, minRange, maxRange - ) - } - return "" - } - - override fun setData(data: BarData?) { - super.setData(data) - } +// override val width: Int +// get() = TODO("Not yet implemented") +// override val height: Int +// get() = TODO("Not yet implemented") } 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 index 77d15a120..bf8e000b5 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.java +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarLineChartBase.java @@ -160,17 +160,17 @@ protected void init() { mAxisLeft = new YAxis(AxisDependency.LEFT); mAxisRight = new YAxis(AxisDependency.RIGHT); - mLeftAxisTransformer = new Transformer(mViewPortHandler); - mRightAxisTransformer = new Transformer(mViewPortHandler); + mLeftAxisTransformer = new Transformer(getViewPortHandler()); + mRightAxisTransformer = new Transformer(getViewPortHandler()); - mAxisRendererLeft = new YAxisRenderer(mViewPortHandler, mAxisLeft, mLeftAxisTransformer); - mAxisRendererRight = new YAxisRenderer(mViewPortHandler, mAxisRight, mRightAxisTransformer); + mAxisRendererLeft = new YAxisRenderer(getViewPortHandler(), mAxisLeft, mLeftAxisTransformer); + mAxisRendererRight = new YAxisRenderer(getViewPortHandler(), mAxisRight, mRightAxisTransformer); - mXAxisRenderer = new XAxisRenderer(mViewPortHandler, mXAxis, mLeftAxisTransformer); + mXAxisRenderer = new XAxisRenderer(getViewPortHandler(), mXAxis, mLeftAxisTransformer); - setHighlighter(new ChartHighlighter(this)); + setHighlighter(new ChartHighlighter<>(this)); - mChartTouchListener = new BarLineChartTouchListener(this, mViewPortHandler.getMatrixTouch(), 3f); + mChartTouchListener = new BarLineChartTouchListener(this, getViewPortHandler().getMatrixTouch(), 3f); mGridBackgroundPaint = new Paint(); mGridBackgroundPaint.setStyle(Style.FILL); @@ -220,7 +220,7 @@ protected void onDraw(@NonNull Canvas canvas) { // Y-axis labels could have changed in size affecting the offsets if (mAutoScaleMinMaxEnabled) { calculateOffsets(); - mViewPortHandler.refresh(mViewPortHandler.getMatrixTouch(), this, false); + getViewPortHandler().refresh(getViewPortHandler().getMatrixTouch(), this, false); } mXAxisRenderer.renderAxisLine(canvas); @@ -255,7 +255,7 @@ protected void onDraw(@NonNull Canvas canvas) { if (isClipDataToContentEnabled()) { // make sure the data cannot be drawn outside the content-rect - canvas.clipRect(mViewPortHandler.getContentRect()); + canvas.clipRect(getViewPortHandler().getContentRect()); } mRenderer.drawData(canvas); @@ -274,7 +274,7 @@ protected void onDraw(@NonNull Canvas canvas) { // if highlighting is enabled if (valuesToHighlight()) { - mRenderer.drawHighlighted(canvas, mIndicesToHighlight); + mRenderer.drawHighlighted(canvas, getHighlighted()); } // Removes clipping rectangle @@ -300,7 +300,7 @@ protected void onDraw(@NonNull Canvas canvas) { if (isClipValuesToContentEnabled()) { clipRestoreCount = canvas.save(); - canvas.clipRect(mViewPortHandler.getContentRect()); + canvas.clipRect(getViewPortHandler().getContentRect()); mRenderer.drawValues(canvas); @@ -309,13 +309,13 @@ protected void onDraw(@NonNull Canvas canvas) { mRenderer.drawValues(canvas); } - mLegendRenderer.renderLegend(canvas); + getLegendRenderer().renderLegend(canvas); drawDescription(canvas); drawMarkers(canvas); - if (mLogEnabled) { + if (isLogEnabled()) { long drawtime = (System.currentTimeMillis() - starttime); totalTime += drawtime; drawCycles += 1; @@ -334,7 +334,7 @@ public void resetTracking() { protected void prepareValuePxMatrix() { - if (mLogEnabled) { + if (isLogEnabled()) { Log.i(LOG_TAG, "Preparing Value-Px Matrix, xmin: " + mXAxis.mAxisMinimum + ", xmax: " + mXAxis.mAxisMaximum + ", xdelta: " + mXAxis.mAxisRange); } @@ -352,12 +352,12 @@ protected void prepareOffsetMatrix() { public void notifyDataSetChanged() { if (mData == null) { - if (mLogEnabled) { + if (isLogEnabled()) { Log.i(LOG_TAG, "Preparing... DATA NOT SET."); } return; } else { - if (mLogEnabled) { + if (isLogEnabled()) { Log.i(LOG_TAG, "Preparing..."); } } @@ -372,8 +372,8 @@ public void notifyDataSetChanged() { mAxisRendererRight.computeAxis(mAxisRight.mAxisMinimum, mAxisRight.mAxisMaximum, mAxisRight.isInverted()); mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false); - if (mLegend != null) { - mLegendRenderer.computeLegend(mData); + if (getLegend() != null) { + getLegendRenderer().computeLegend(mData); } calculateOffsets(); @@ -409,31 +409,31 @@ protected void calculateLegendOffsets(RectF offsets) { offsets.top = 0.f; offsets.bottom = 0.f; - if (mLegend == null || !mLegend.isEnabled() || mLegend.isDrawInsideEnabled()) { + if (getLegend() == null || !getLegend().isEnabled() || getLegend().isDrawInsideEnabled()) { return; } - switch (mLegend.getOrientation()) { + switch (getLegend().getOrientation()) { case VERTICAL: - switch (mLegend.getHorizontalAlignment()) { + switch (getLegend().getHorizontalAlignment()) { case LEFT: - offsets.left += Math.min(mLegend.mNeededWidth, mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent()) + mLegend.getXOffset(); + offsets.left += Math.min(getLegend().mNeededWidth, getViewPortHandler().getChartWidth() * getLegend().getMaxSizePercent()) + getLegend().getXOffset(); break; case RIGHT: - offsets.right += Math.min(mLegend.mNeededWidth, mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent()) + mLegend.getXOffset(); + offsets.right += Math.min(getLegend().mNeededWidth, getViewPortHandler().getChartWidth() * getLegend().getMaxSizePercent()) + getLegend().getXOffset(); break; case CENTER: - switch (mLegend.getVerticalAlignment()) { + switch (getLegend().getVerticalAlignment()) { case TOP: - offsets.top += Math.min(mLegend.mNeededHeight, mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) + mLegend.getYOffset(); + offsets.top += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); break; case BOTTOM: - offsets.bottom += Math.min(mLegend.mNeededHeight, mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) + mLegend.getYOffset(); + offsets.bottom += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); break; default: @@ -445,15 +445,15 @@ protected void calculateLegendOffsets(RectF offsets) { case HORIZONTAL: - switch (mLegend.getVerticalAlignment()) { + switch (getLegend().getVerticalAlignment()) { case TOP: - offsets.top += Math.min(mLegend.mNeededHeight, mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) + mLegend.getYOffset(); + offsets.top += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); break; case BOTTOM: - offsets.bottom += Math.min(mLegend.mNeededHeight, mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()) + mLegend.getYOffset(); + offsets.bottom += Math.min(getLegend().mNeededHeight, getViewPortHandler().getChartHeight() * getLegend().getMaxSizePercent()) + getLegend().getYOffset(); break; @@ -517,11 +517,11 @@ public void calculateOffsets() { float minOffset = UtilsKtKt.convertDpToPixel(mMinOffset); - mViewPortHandler.restrainViewPort(Math.max(minOffset, offsetLeft), Math.max(minOffset, offsetTop), Math.max(minOffset, offsetRight), Math.max(minOffset, offsetBottom)); + getViewPortHandler().restrainViewPort(Math.max(minOffset, offsetLeft), Math.max(minOffset, offsetTop), Math.max(minOffset, offsetRight), Math.max(minOffset, offsetBottom)); - if (mLogEnabled) { + if (isLogEnabled()) { Log.i(LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom); - Log.i(LOG_TAG, "Content: " + mViewPortHandler.getContentRect()); + Log.i(LOG_TAG, "Content: " + getViewPortHandler().getContentRect()); } } @@ -537,11 +537,11 @@ protected void drawGridBackground(Canvas c) { if (mDrawGridBackground) { // draw the grid background - c.drawRect(mViewPortHandler.getContentRect(), mGridBackgroundPaint); + c.drawRect(getViewPortHandler().getContentRect(), mGridBackgroundPaint); } if (mDrawBorders) { - c.drawRect(mViewPortHandler.getContentRect(), mBorderPaint); + c.drawRect(getViewPortHandler().getContentRect(), mBorderPaint); } } @@ -594,10 +594,10 @@ public void computeScroll() { */ public void zoomIn() { - MPPointF center = mViewPortHandler.getContentCenter(); + MPPointF center = getViewPortHandler().getContentCenter(); - mViewPortHandler.zoomIn(center.getX(), -center.getY(), mZoomMatrixBuffer); - mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); + getViewPortHandler().zoomIn(center.getX(), -center.getY(), mZoomMatrixBuffer); + getViewPortHandler().refresh(mZoomMatrixBuffer, this, false); MPPointF.recycleInstance(center); @@ -613,10 +613,10 @@ public void zoomIn() { */ public void zoomOut() { - MPPointF center = mViewPortHandler.getContentCenter(); + MPPointF center = getViewPortHandler().getContentCenter(); - mViewPortHandler.zoomOut(center.getX(), -center.getY(), mZoomMatrixBuffer); - mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); + getViewPortHandler().zoomOut(center.getX(), -center.getY(), mZoomMatrixBuffer); + getViewPortHandler().refresh(mZoomMatrixBuffer, this, false); MPPointF.recycleInstance(center); @@ -632,8 +632,8 @@ public void zoomOut() { */ public void resetZoom() { - mViewPortHandler.resetZoom(mZoomMatrixBuffer); - mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); + 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. @@ -651,8 +651,8 @@ public void resetZoom() { */ public void zoom(float scaleX, float scaleY, float x, float y) { - mViewPortHandler.zoom(scaleX, scaleY, x, -y, mZoomMatrixBuffer); - mViewPortHandler.refresh(mZoomMatrixBuffer, this, false); + 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. @@ -669,7 +669,7 @@ public void zoom(float scaleX, float scaleY, float x, float y) { */ public void zoom(float scaleX, float scaleY, float xValue, float yValue, AxisDependency axis) { - Runnable job = ZoomJob.Companion.getInstance(mViewPortHandler, scaleX, scaleY, xValue, yValue, getTransformer(axis), axis, this); + Runnable job = ZoomJob.Companion.getInstance(getViewPortHandler(), scaleX, scaleY, xValue, yValue, getTransformer(axis), axis, this); addViewportJob(job); } @@ -681,8 +681,8 @@ public void zoomToCenter(float scaleX, float scaleY) { MPPointF center = getCenterOffsets(); Matrix save = mZoomMatrixBuffer; - mViewPortHandler.zoom(scaleX, scaleY, center.getX(), -center.getY(), save); - mViewPortHandler.refresh(save, this, false); + getViewPortHandler().zoom(scaleX, scaleY, center.getX(), -center.getY(), save); + getViewPortHandler().refresh(save, this, false); } /** @@ -690,9 +690,9 @@ public void zoomToCenter(float scaleX, float scaleY) { */ public void zoomAndCenterAnimated(float scaleX, float scaleY, float xValue, float yValue, AxisDependency axis, long duration) { - MPPointD origin = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis); + MPPointD origin = getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentTop(), axis); - Runnable job = AnimatedZoomJob.Companion.getInstance(mViewPortHandler, this, getTransformer(axis), getAxis(axis), mXAxis.mAxisRange, scaleX, scaleY, mViewPortHandler.getScaleX(), mViewPortHandler.getScaleY(), xValue, yValue, (float) origin.getX(), (float) origin.getY(), duration); + 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); @@ -706,8 +706,8 @@ public void zoomAndCenterAnimated(float scaleX, float scaleY, float xValue, floa */ public void fitScreen() { Matrix save = mFitScreenMatrixBuffer; - mViewPortHandler.fitScreen(save); - mViewPortHandler.refresh(save, this, false); + getViewPortHandler().fitScreen(save); + getViewPortHandler().refresh(save, this, false); calculateOffsets(); postInvalidate(); @@ -718,8 +718,8 @@ public void fitScreen() { * fitScreen */ public void setScaleMinima(float scaleX, float scaleY) { - mViewPortHandler.setMinimumScaleX(scaleX); - mViewPortHandler.setMinimumScaleY(scaleY); + getViewPortHandler().setMinimumScaleX(scaleX); + getViewPortHandler().setMinimumScaleY(scaleY); } /** @@ -732,7 +732,7 @@ public void setScaleMinima(float scaleX, float scaleY) { */ public void setVisibleXRangeMaximum(float maxXRange) { float xScale = mXAxis.mAxisRange / (maxXRange); - mViewPortHandler.setMinimumScaleX(xScale); + getViewPortHandler().setMinimumScaleX(xScale); } /** @@ -745,7 +745,7 @@ public void setVisibleXRangeMaximum(float maxXRange) { */ public void setVisibleXRangeMinimum(float minXRange) { float xScale = mXAxis.mAxisRange / (minXRange); - mViewPortHandler.setMaximumScaleX(xScale); + getViewPortHandler().setMaximumScaleX(xScale); } /** @@ -756,7 +756,7 @@ public void setVisibleXRangeMinimum(float minXRange) { public void setVisibleXRange(float minXRange, float maxXRange) { float minScale = mXAxis.mAxisRange / minXRange; float maxScale = mXAxis.mAxisRange / maxXRange; - mViewPortHandler.setMinMaxScaleX(minScale, maxScale); + getViewPortHandler().setMinMaxScaleX(minScale, maxScale); } /** @@ -768,7 +768,7 @@ public void setVisibleXRange(float minXRange, float maxXRange) { */ public void setVisibleYRangeMaximum(float maxYRange, AxisDependency axis) { float yScale = getAxisRange(axis) / maxYRange; - mViewPortHandler.setMinimumScaleY(yScale); + getViewPortHandler().setMinimumScaleY(yScale); } /** @@ -778,7 +778,7 @@ public void setVisibleYRangeMaximum(float maxYRange, AxisDependency axis) { */ public void setVisibleYRangeMinimum(float minYRange, AxisDependency axis) { float yScale = getAxisRange(axis) / minYRange; - mViewPortHandler.setMaximumScaleY(yScale); + getViewPortHandler().setMaximumScaleY(yScale); } /** @@ -787,7 +787,7 @@ public void setVisibleYRangeMinimum(float minYRange, AxisDependency axis) { public void setVisibleYRange(float minYRange, float maxYRange, AxisDependency axis) { float minScale = getAxisRange(axis) / minYRange; float maxScale = getAxisRange(axis) / maxYRange; - mViewPortHandler.setMinMaxScaleY(minScale, maxScale); + getViewPortHandler().setMinMaxScaleY(minScale, maxScale); } @@ -797,7 +797,7 @@ public void setVisibleYRange(float minYRange, float maxYRange, AxisDependency ax */ public void moveViewToX(float xValue) { - Runnable job = MoveViewJob.Companion.getInstance(mViewPortHandler, xValue, 0f, getTransformer(AxisDependency.LEFT), this); + Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), xValue, 0f, getTransformer(AxisDependency.LEFT), this); addViewportJob(job); } @@ -811,9 +811,9 @@ public void moveViewToX(float xValue) { */ public void moveViewTo(float xValue, float yValue, AxisDependency axis) { - float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); + float yInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); - Runnable job = MoveViewJob.Companion.getInstance(mViewPortHandler, xValue, yValue + yInView / 2f, getTransformer(axis), this); + Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), xValue, yValue + yInView / 2f, getTransformer(axis), this); addViewportJob(job); } @@ -827,11 +827,11 @@ public void moveViewTo(float xValue, float yValue, AxisDependency axis) { */ public void moveViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) { - MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis); + MPPointD bounds = getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentTop(), axis); - float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); + float yInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); - Runnable job = AnimatedMoveViewJob.Companion.getInstance(mViewPortHandler, xValue, yValue + yInView / 2f, getTransformer(axis), this, (float) bounds.getX(), (float) bounds.getY(), duration); + Runnable job = AnimatedMoveViewJob.Companion.getInstance(getViewPortHandler(), xValue, yValue + yInView / 2f, getTransformer(axis), this, (float) bounds.getX(), (float) bounds.getY(), duration); addViewportJob(job); @@ -846,9 +846,9 @@ public void moveViewToAnimated(float xValue, float yValue, AxisDependency axis, */ public void centerViewToY(float yValue, AxisDependency axis) { - float valsInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); + float valsInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); - Runnable job = MoveViewJob.Companion.getInstance(mViewPortHandler, 0f, yValue + valsInView / 2f, getTransformer(axis), this); + Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), 0f, yValue + valsInView / 2f, getTransformer(axis), this); addViewportJob(job); } @@ -862,10 +862,10 @@ public void centerViewToY(float yValue, AxisDependency axis) { */ public void centerViewTo(float xValue, float yValue, AxisDependency axis) { - float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); - float xInView = getXAxis().mAxisRange / mViewPortHandler.getScaleX(); + float yInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); + float xInView = getXAxis().mAxisRange / getViewPortHandler().getScaleX(); - Runnable job = MoveViewJob.Companion.getInstance(mViewPortHandler, xValue - xInView / 2f, yValue + yInView / 2f, getTransformer(axis), this); + Runnable job = MoveViewJob.Companion.getInstance(getViewPortHandler(), xValue - xInView / 2f, yValue + yInView / 2f, getTransformer(axis), this); addViewportJob(job); } @@ -878,12 +878,12 @@ public void centerViewTo(float xValue, float yValue, AxisDependency axis) { */ public void centerViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) { - MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis); + MPPointD bounds = getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentTop(), axis); - float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY(); - float xInView = getXAxis().mAxisRange / mViewPortHandler.getScaleX(); + float yInView = getAxisRange(axis) / getViewPortHandler().getScaleY(); + float xInView = getXAxis().mAxisRange / getViewPortHandler().getScaleX(); - Runnable job = AnimatedMoveViewJob.Companion.getInstance(mViewPortHandler, xValue - xInView / 2f, yValue + yInView / 2f, getTransformer(axis), this, (float) bounds.getX(), (float) bounds.getY(), duration); + Runnable job = AnimatedMoveViewJob.Companion.getInstance(getViewPortHandler(), xValue - xInView / 2f, yValue + yInView / 2f, getTransformer(axis), this, (float) bounds.getX(), (float) bounds.getY(), duration); addViewportJob(job); @@ -910,7 +910,7 @@ public void setViewPortOffsets(final float left, final float top, final float ri @Override public void run() { - mViewPortHandler.restrainViewPort(left, top, right, bottom); + getViewPortHandler().restrainViewPort(left, top, right, bottom); prepareOffsetMatrix(); prepareValuePxMatrix(); } @@ -1259,7 +1259,7 @@ public IBarLineScatterCandleBubbleDataSet getDataSetByTouchPoint(float x, float */ @Override public float getLowestVisibleX() { - getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom(), posForGetLowestVisibleX); + getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(getViewPortHandler().contentLeft(), getViewPortHandler().contentBottom(), posForGetLowestVisibleX); return (float) Math.max(mXAxis.mAxisMinimum, posForGetLowestVisibleX.getX()); } @@ -1274,7 +1274,7 @@ public float getLowestVisibleX() { */ @Override public float getHighestVisibleX() { - getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(mViewPortHandler.contentRight(), mViewPortHandler.contentBottom(), posForGetHighestVisibleX); + getTransformer(AxisDependency.LEFT).getValuesByTouchPoint(getViewPortHandler().contentRight(), getViewPortHandler().contentBottom(), posForGetHighestVisibleX); return (float) Math.min(mXAxis.mAxisMaximum, posForGetHighestVisibleX.getX()); } @@ -1289,10 +1289,10 @@ public float getVisibleXRange() { * returns the current x-scale factor */ public float getScaleX() { - if (mViewPortHandler == null) { + if (getViewPortHandler() == null) { return 1f; } else { - return mViewPortHandler.getScaleX(); + return getViewPortHandler().getScaleX(); } } @@ -1300,10 +1300,10 @@ public float getScaleX() { * returns the current y-scale factor */ public float getScaleY() { - if (mViewPortHandler == null) { + if (getViewPortHandler() == null) { return 1f; } else { - return mViewPortHandler.getScaleY(); + return getViewPortHandler().getScaleY(); } } @@ -1311,7 +1311,7 @@ public float getScaleY() { * if the chart is fully zoomed out, return true */ public boolean isFullyZoomedOut() { - return mViewPortHandler.isFullyZoomedOut(); + return getViewPortHandler().isFullyZoomedOut(); } /** @@ -1367,7 +1367,7 @@ public boolean isPinchZoomEnabled() { * bounds on the x-axis. */ public void setDragOffsetX(float offset) { - mViewPortHandler.setDragOffsetX(offset); + getViewPortHandler().setDragOffsetX(offset); } /** @@ -1375,14 +1375,14 @@ public void setDragOffsetX(float offset) { * bounds on the y-axis. */ public void setDragOffsetY(float offset) { - mViewPortHandler.setDragOffsetY(offset); + getViewPortHandler().setDragOffsetY(offset); } /** * Returns true if both drag offsets (x and y) are zero or smaller. */ public boolean hasNoDragOffset() { - return mViewPortHandler.hasNoDragOffset(); + return getViewPortHandler().hasNoDragOffset(); } public XAxisRenderer getRendererXAxis() { @@ -1489,8 +1489,8 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { mOnSizeChangedBuffer[0] = mOnSizeChangedBuffer[1] = 0; if (mKeepPositionOnRotation) { - mOnSizeChangedBuffer[0] = mViewPortHandler.contentLeft(); - mOnSizeChangedBuffer[1] = mViewPortHandler.contentTop(); + mOnSizeChangedBuffer[0] = getViewPortHandler().contentLeft(); + mOnSizeChangedBuffer[1] = getViewPortHandler().contentTop(); getTransformer(AxisDependency.LEFT).pixelsToValue(mOnSizeChangedBuffer); } @@ -1501,9 +1501,9 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { //Restoring old position of chart. getTransformer(AxisDependency.LEFT).pointValuesToPixel(mOnSizeChangedBuffer); - mViewPortHandler.centerViewPort(mOnSizeChangedBuffer, this); + getViewPortHandler().centerViewPort(mOnSizeChangedBuffer, this); } else { - mViewPortHandler.refresh(mViewPortHandler.getMatrixTouch(), this, true); + getViewPortHandler().refresh(getViewPortHandler().getMatrixTouch(), this, true); } } 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 1d95e5a0b..e20e810f5 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 @@ -3,7 +3,6 @@ package com.github.mikephil.charting.charts import android.content.Context import android.util.AttributeSet import com.github.mikephil.charting.data.BubbleData -import com.github.mikephil.charting.data.ChartData import com.github.mikephil.charting.interfaces.dataprovider.BubbleDataProvider import com.github.mikephil.charting.renderer.BubbleChartRenderer @@ -20,20 +19,15 @@ class BubbleChart : BarLineChartBase, BubbleDataProvider { constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) - protected override fun init() { + override fun init() { super.init() - mRenderer = BubbleChartRenderer(this, mAnimator, mViewPortHandler) + mRenderer = BubbleChartRenderer(this, mAnimator, viewPortHandler) } override val bubbleData: BubbleData? get() = mData - override fun getAccessibilityDescription(): String { - return "This is bubble chart" - } - - override fun setData(data: BubbleData?) { - super.setData(data) - } + override val accessibilityDescription: String + get() = "This is bubble chart" } 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 c391e049d..1ffc56251 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 @@ -17,10 +17,10 @@ class CandleStickChart : BarLineChartBase, CandleDataProvider { constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) - protected override fun init() { + override fun init() { super.init() - mRenderer = CandleStickChartRenderer(this, mAnimator, mViewPortHandler) + mRenderer = CandleStickChartRenderer(this, mAnimator, viewPortHandler) xAxis.spaceMin = 0.5f xAxis.spaceMax = 0.5f @@ -29,11 +29,6 @@ class CandleStickChart : BarLineChartBase, CandleDataProvider { override val candleData: CandleData? get() = mData - override fun getAccessibilityDescription(): String { - return "This is a candlestick chart" - } - - override fun setData(data: CandleData?) { - super.setData(data) - } + override val accessibilityDescription: String + get() = "This is a candlestick chart" } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.java b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.java deleted file mode 100644 index 50796dc61..000000000 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.java +++ /dev/null @@ -1,1632 +0,0 @@ -package com.github.mikephil.charting.charts; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Align; -import android.graphics.RectF; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.accessibility.AccessibilityEvent; - -import com.github.mikephil.charting.animation.ChartAnimator; -import com.github.mikephil.charting.animation.Easing.EasingFunction; -import com.github.mikephil.charting.components.Description; -import com.github.mikephil.charting.components.IMarker; -import com.github.mikephil.charting.components.Legend; -import com.github.mikephil.charting.components.XAxis; -import com.github.mikephil.charting.data.ChartData; -import com.github.mikephil.charting.data.Entry; -import com.github.mikephil.charting.formatter.DefaultValueFormatter; -import com.github.mikephil.charting.formatter.IValueFormatter; -import com.github.mikephil.charting.highlight.ChartHighlighter; -import com.github.mikephil.charting.highlight.Highlight; -import com.github.mikephil.charting.highlight.IHighlighter; -import com.github.mikephil.charting.interfaces.dataprovider.base.IBaseProvider; -import com.github.mikephil.charting.interfaces.datasets.IDataSet; -import com.github.mikephil.charting.listener.ChartTouchListener; -import com.github.mikephil.charting.listener.OnChartGestureListener; -import com.github.mikephil.charting.listener.OnChartValueSelectedListener; -import com.github.mikephil.charting.renderer.DataRenderer; -import com.github.mikephil.charting.renderer.LegendRenderer; -import com.github.mikephil.charting.utils.MPPointF; -import com.github.mikephil.charting.utils.SaveUtils; -import com.github.mikephil.charting.utils.Utils; -import com.github.mikephil.charting.utils.UtilsKtKt; -import com.github.mikephil.charting.utils.ViewPortHandler; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -/** - * Baseclass of all Chart-Views. - * - * @author Philipp Jahoda - */ -@SuppressWarnings("unused") -public abstract class Chart>> extends ViewGroup implements IBaseProvider { - - public static final String LOG_TAG = "AndroidChart"; - - /** - * flag that indicates if logging is enabled or not - */ - protected boolean mLogEnabled = false; - - /** - * object that holds all data that was originally set for the chart, before - * it was modified or any filtering algorithms had been applied - */ - @Nullable - protected T mData = null; - - /** - * Flag that indicates if highlighting per tap (touch) is enabled - */ - protected boolean mHighLightPerTapEnabled = true; - - /** - * If set to true, chart continues to scroll after touch up - */ - private boolean mDragDecelerationEnabled = true; - - /** - * Deceleration friction coefficient in [0 ; 1] interval, higher values - * indicate that speed will decrease slowly, for example if it set to 0, it - * will stop immediately. 1 is an invalid value, and will be converted to - * 0.999f automatically. - */ - private float mDragDecelerationFrictionCoef = 0.9f; - - /** - * default value-formatter, number of digits depends on provided chart-data - */ - protected DefaultValueFormatter mDefaultValueFormatter = new DefaultValueFormatter(0); - - /** - * paint object used for drawing the description text in the bottom right - * corner of the chart - */ - protected Paint mDescPaint; - - /** - * paint object for drawing the information text when there are no values in - * the chart - */ - protected Paint mInfoPaint; - - /** - * the object representing the labels on the x-axis - */ - protected XAxis mXAxis; - - /** - * if true, touch gestures are enabled on the chart - */ - protected boolean mTouchEnabled = true; - - /** - * the object responsible for representing the description text - */ - protected Description mDescription; - - /** - * the legend object containing all data associated with the legend - */ - protected Legend mLegend; - - /** - * listener that is called when a value on the chart is selected - */ - protected OnChartValueSelectedListener mSelectionListener; - - protected ChartTouchListener mChartTouchListener; - - /** - * text that is displayed when the chart is empty - */ - private String mNoDataText = "No chart data available."; - - /** - * Gesture listener for custom callbacks when making gestures on the chart. - */ - private OnChartGestureListener mGestureListener; - - protected LegendRenderer mLegendRenderer; - - /** - * object responsible for rendering the data - */ - protected DataRenderer mRenderer; - - protected IHighlighter mHighlighter; - - /** - * object that manages the bounds and drawing constraints of the chart - */ - protected ViewPortHandler mViewPortHandler = new ViewPortHandler(); - - /** - * object responsible for animations - */ - protected ChartAnimator mAnimator; - - /** - * Extra offsets to be appended to the viewport - */ - private float mExtraTopOffset = 0.f, mExtraRightOffset = 0.f, mExtraBottomOffset = 0.f, mExtraLeftOffset = 0.f; - - /** - * Additional data on top of dynamically generated description. This can be set by the user. - */ - private String accessibilitySummaryDescription = ""; - - /** - * default constructor for initialization in code - */ - public Chart(Context context) { - super(context); - init(); - } - - /** - * constructor for initialization in xml - */ - public Chart(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - /** - * even more awesome constructor - */ - public Chart(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - /** - * initialize all paints and stuff - */ - protected void init() { - - setWillNotDraw(false); - // setLayerType(View.LAYER_TYPE_HARDWARE, null); - - mAnimator = new ChartAnimator(animation -> { - // ViewCompat.postInvalidateOnAnimation(Chart.this); - postInvalidate(); - }); - - // initialize the utils - Utils.init(getContext()); - UtilsKtKt.initUtils(getContext()); - mMaxHighlightDistance = UtilsKtKt.convertDpToPixel(500f); - - mDescription = new Description(); - mLegend = new Legend(); - - mLegendRenderer = new LegendRenderer(mViewPortHandler, mLegend); - - mXAxis = new XAxis(); - - mDescPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - - mInfoPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mInfoPaint.setColor(Color.rgb(247, 189, 51)); // orange - mInfoPaint.setTextAlign(Align.CENTER); - mInfoPaint.setTextSize(UtilsKtKt.convertDpToPixel(12f)); - - if (mLogEnabled) { - Log.i("", "Chart.init()"); - - // enable being detected by ScreenReader - setFocusable(true); - } - } - - // public void initWithDummyData() { - // ColorTemplate template = new ColorTemplate(); - // template.addColorsForDataSets(ColorTemplate.COLORFUL_COLORS, - // getContext()); - // - // setColorTemplate(template); - // setDrawYValues(false); - // - // ArrayList xVals = new ArrayList(); - // Calendar calendar = Calendar.getInstance(); - // for (int i = 0; i < 12; i++) { - // xVals.add(calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, - // Locale.getDefault())); - // } - // - // ArrayList dataSets = new ArrayList(); - // for (int i = 0; i < 3; i++) { - // - // ArrayList yVals = new ArrayList(); - // - // for (int j = 0; j < 12; j++) { - // float val = (float) (Math.random() * 100); - // yVals.add(new Entry(val, j)); - // } - // - // DataSet set = new DataSet(yVals, "DataSet " + i); - // dataSets.add(set); // add the datasets - // } - // // create a data object with the datasets - // ChartData data = new ChartData(xVals, dataSets); - // setData(data); - // invalidate(); - // } - - /** - * Sets a new data object for the chart. The data object contains all values - * and information needed for displaying. - */ - public void setData(T data) { - - mData = data; - mOffsetsCalculated = false; - - if (data == null) { - return; - } - - // calculate how many digits are needed - setupDefaultFormatter(data.getYMin(), data.getYMax()); - - for (IDataSet set : mData.getDataSets()) { - if (set.needsFormatter() || set.getValueFormatter() == mDefaultValueFormatter) { - set.setValueFormatter(mDefaultValueFormatter); - } - } - - // let the chart know there is new data - notifyDataSetChanged(); - - if (mLogEnabled) { - Log.i(LOG_TAG, "Data is set."); - } - } - - /** - * Clears the chart from all data (sets it to null) and refreshes it (by - * calling invalidate()). - */ - public void clear() { - mData = null; - mOffsetsCalculated = false; - mIndicesToHighlight = null; - mChartTouchListener.setLastHighlighted(null); - invalidate(); - } - - /** - * Removes all DataSets (and thereby Entries) from the chart. Does not set the data object to null. Also refreshes the - * chart by calling invalidate(). - */ - public void clearValues() { - mData.clearValues(); - invalidate(); - } - - /** - * Returns true if the chart is empty (meaning it's data object is either - * null or contains no entries). - */ - public boolean isEmpty() { - if (mData == null) { - return true; - } else { - return mData.getEntryCount() <= 0; - } - } - - /** - * Lets the chart know its underlying data has changed and performs all - * necessary recalculations. It is crucial that this method is called - * everytime data is changed dynamically. Not calling this method can lead - * to crashes or unexpected behaviour. - */ - public abstract void notifyDataSetChanged(); - - /** - * Calculates the offsets of the chart to the border depending on the - * position of an eventual legend or depending on the length of the y-axis - * and x-axis labels and their position - */ - protected abstract void calculateOffsets(); - - /** - * Calculates the y-min and y-max value and the y-delta and x-delta value - */ - protected abstract void calcMinMax(); - - /** - * Calculates the required number of digits for the values that might be - * drawn in the chart (if enabled), and creates the default-value-formatter - */ - protected void setupDefaultFormatter(float min, float max) { - - float reference; - - if (mData == null || mData.getEntryCount() < 2) { - reference = Math.max(Math.abs(min), Math.abs(max)); - } else { - reference = Math.abs(max - min); - } - - int digits = UtilsKtKt.getDecimals(reference); - - // setup the formatter with a new number of digits - mDefaultValueFormatter.setup(digits); - } - - /** - * flag that indicates if offsets calculation has already been done or not - */ - private boolean mOffsetsCalculated = false; - - @Override - protected void onDraw(@NonNull Canvas canvas) { - // super.onDraw(canvas); - - if (mData == null) { - - boolean hasText = !TextUtils.isEmpty(mNoDataText); - - if (hasText) { - MPPointF pt = getCenter(); - - switch (mInfoPaint.getTextAlign()) { - case LEFT: - pt.setX(0); - canvas.drawText(mNoDataText, pt.getX(), pt.getY(), mInfoPaint); - break; - - case RIGHT: - pt.setX(pt.getX() * 2.0F); - canvas.drawText(mNoDataText, pt.getX(), pt.getY(), mInfoPaint); - break; - - default: - canvas.drawText(mNoDataText, pt.getX(), pt.getY(), mInfoPaint); - break; - } - } - - return; - } - - if (!mOffsetsCalculated) { - - calculateOffsets(); - mOffsetsCalculated = true; - } - } - - /** - * Draws the description text in the bottom right corner of the chart (per default) - */ - protected void drawDescription(Canvas c) { - - // check if description should be drawn - if (mDescription != null && mDescription.isEnabled()) { - - MPPointF position = mDescription.getPosition(); - - mDescPaint.setTypeface(mDescription.getTypeface()); - mDescPaint.setTextSize(mDescription.getTextSize()); - mDescPaint.setColor(mDescription.getTextColor()); - mDescPaint.setTextAlign(mDescription.getTextAlign()); - - float x, y; - - // if no position specified, draw on default position - if (position == null) { - x = getWidth() - mViewPortHandler.offsetRight() - mDescription.getXOffset(); - y = getHeight() - mViewPortHandler.offsetBottom() - mDescription.getYOffset(); - } else { - x = position.getX(); - y = position.getY(); - } - - c.drawText(mDescription.text, x, y, mDescPaint); - } - } - - /** - * array of Highlight objects that reference the highlighted slices in the - * chart - */ - protected Highlight[] mIndicesToHighlight; - - /** - * The maximum distance in dp away from an entry causing it to highlight. - */ - protected float mMaxHighlightDistance = 0f; - - @Override - public float getMaxHighlightDistance() { - return mMaxHighlightDistance; - } - - /** - * Sets the maximum distance in screen dp a touch can be away from an entry to cause it to get highlighted. - * Default: 500dp - */ - public void setMaxHighlightDistance(float distDp) { - mMaxHighlightDistance = UtilsKtKt.convertDpToPixel(distDp); - } - - /** - * Returns the array of currently highlighted values. This might a null or - * empty array if nothing is highlighted. - */ - public Highlight[] getHighlighted() { - return mIndicesToHighlight; - } - - /** - * Returns true if values can be highlighted via tap gesture, false if not. - */ - public boolean isHighlightPerTapEnabled() { - return mHighLightPerTapEnabled; - } - - /** - * Set this to false to prevent values from being highlighted by tap gesture. - * Values can still be highlighted via drag or programmatically. Default: true - */ - public void setHighlightPerTapEnabled(boolean enabled) { - mHighLightPerTapEnabled = enabled; - } - - /** - * Returns true if there are values to highlight, false if there are no - * values to highlight. Checks if the highlight array is null, has a length - * of zero or if the first object is null. - */ - public boolean valuesToHighlight() { - return mIndicesToHighlight != null && mIndicesToHighlight.length > 0 && mIndicesToHighlight[0] != null; - } - - /** - * Sets the last highlighted value for the touchlistener. - */ - protected void setLastHighlighted(Highlight[] highs) { - - if (highs == null || highs.length <= 0 || highs[0] == null) { - mChartTouchListener.setLastHighlighted(null); - } else { - mChartTouchListener.setLastHighlighted(highs[0]); - } - } - - /** - * Highlights the values at the given indices in the given DataSets. Provide - * null or an empty array to undo all highlighting. This should be used to - * programmatically highlight values. - * This method *will not* call the listener. - */ - public void highlightValues(Highlight[] highs) { - - // set the indices to highlight - mIndicesToHighlight = highs; - - setLastHighlighted(highs); - - // redraw the chart - invalidate(); - } - - public void highlightValues(List highs, List markers) { - if (highs.size() != markers.size()) { - throw new IllegalArgumentException("Markers and highs must be mutually corresponding. High size = " + highs.size() + " Markers size = " + markers.size()); - } - setMarkers(markers); - highlightValues(highs.toArray(new Highlight[0])); - } - - /** - * Highlights any y-value at the given x-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * This method will call the listener. - * * @param x The x-value to highlight - * - * @param dataSetIndex The dataset index to search in - * @param dataIndex The data index to search in (only used in CombinedChartView currently) - */ - public void highlightValue(float x, int dataSetIndex, int dataIndex) { - highlightValue(x, dataSetIndex, dataIndex, true); - } - - /** - * Highlights any y-value at the given x-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * This method will call the listener. - * - * @param x The x-value to highlight - * @param dataSetIndex The dataset index to search in - */ - public void highlightValue(float x, int dataSetIndex) { - highlightValue(x, dataSetIndex, -1, true); - } - - /** - * Highlights the value at the given x-value and y-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * This method will call the listener. - * - * @param x The x-value to highlight - * @param y The y-value to highlight. Supply `NaN` for "any" - * @param dataSetIndex The dataset index to search in - * @param dataIndex The data index to search in (only used in CombinedChartView currently) - */ - public void highlightValue(float x, float y, int dataSetIndex, int dataIndex) { - highlightValue(x, y, dataSetIndex, dataIndex, true); - } - - /** - * Highlights the value at the given x-value and y-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * This method will call the listener. - * - * @param x The x-value to highlight - * @param y The y-value to highlight. Supply `NaN` for "any" - * @param dataSetIndex The dataset index to search in - */ - public void highlightValue(float x, float y, int dataSetIndex) { - highlightValue(x, y, dataSetIndex, -1, true); - } - - /** - * Highlights any y-value at the given x-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * - * @param x The x-value to highlight - * @param dataSetIndex The dataset index to search in - * @param dataIndex The data index to search in (only used in CombinedChartView currently) - * @param callListener Should the listener be called for this change - */ - public void highlightValue(float x, int dataSetIndex, int dataIndex, boolean callListener) { - highlightValue(x, Float.NaN, dataSetIndex, dataIndex, callListener); - } - - /** - * Highlights any y-value at the given x-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * - * @param x The x-value to highlight - * @param dataSetIndex The dataset index to search in - * @param callListener Should the listener be called for this change - */ - public void highlightValue(float x, int dataSetIndex, boolean callListener) { - highlightValue(x, Float.NaN, dataSetIndex, -1, callListener); - } - - /** - * Highlights any y-value at the given x-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * - * @param x The x-value to highlight - * @param y The y-value to highlight. Supply `NaN` for "any" - * @param dataSetIndex The dataset index to search in - * @param dataIndex The data index to search in (only used in CombinedChartView currently) - * @param callListener Should the listener be called for this change - */ - public void highlightValue(float x, float y, int dataSetIndex, int dataIndex, boolean callListener) { - - if (dataSetIndex < 0 || dataSetIndex >= mData.getDataSetCount()) { - highlightValue(null, callListener); - } else { - highlightValue(new Highlight(x, y, dataSetIndex, dataIndex), callListener); - } - } - - /** - * Highlights any y-value at the given x-value in the given DataSet. - * Provide -1 as the dataSetIndex to undo all highlighting. - * - * @param x The x-value to highlight - * @param y The y-value to highlight. Supply `NaN` for "any" - * @param dataSetIndex The dataset index to search in - * @param callListener Should the listener be called for this change - */ - public void highlightValue(float x, float y, int dataSetIndex, boolean callListener) { - highlightValue(x, y, dataSetIndex, -1, callListener); - } - - /** - * Highlights the values represented by the provided Highlight object - * This method *will not* call the listener. - * - * @param highlight contains information about which entry should be highlighted - */ - public void highlightValue(Highlight highlight) { - highlightValue(highlight, false); - } - - /** - * Highlights the value selected by touch gesture. Unlike - * highlightValues(...), this generates a callback to the - * OnChartValueSelectedListener. - * - * @param high - the highlight object - * @param callListener - call the listener - */ - public void highlightValue(Highlight high, boolean callListener) { - - Entry entry = null; - - if (high == null) { - mIndicesToHighlight = null; - } else { - - if (mLogEnabled) { - Log.i(LOG_TAG, "Highlighted: " + high); - } - - entry = mData.getEntryForHighlight(high); - if (entry == null) { - mIndicesToHighlight = null; - high = null; - } else { - - // set the indices to highlight - mIndicesToHighlight = new Highlight[]{high}; - } - } - - setLastHighlighted(mIndicesToHighlight); - - if (callListener && mSelectionListener != null) { - - if (!valuesToHighlight()) { - mSelectionListener.onNothingSelected(); - } else { - // notify the listener - mSelectionListener.onValueSelected(entry, high); - } - } - - // redraw the chart - invalidate(); - } - - /** - * Returns the Highlight object (contains x-index and DataSet index) of the - * selected value at the given touch point inside the Line-, Scatter-, or - * CandleStick-Chart. - */ - public Highlight getHighlightByTouchPoint(float x, float y) { - - if (mData == null) { - Log.e(LOG_TAG, "Can't select by touch. No data set."); - return null; - } else { - return getHighlighter().getHighlight(x, y); - } - } - - /** - * Set a new (e.g. custom) ChartTouchListener NOTE: make sure to - * setTouchEnabled(true); if you need touch gestures on the chart - */ - public void setOnTouchListener(ChartTouchListener touchListener) { - this.mChartTouchListener = touchListener; - } - - /** - * Returns an instance of the currently active touch listener. - */ - public ChartTouchListener getOnTouchListener() { - return mChartTouchListener; - } - - /** - * if set to true, the marker view is drawn when a value is clicked - */ - protected boolean mDrawMarkers = true; - - /** - * the view that represents the marker - */ - protected List mMarkers = new ArrayList<>(); - - /** - * draws all MarkerViews on the highlighted positions - */ - protected void drawMarkers(Canvas canvas) { - - // if there is no marker view or drawing marker is disabled - if (mMarkers == null || !isDrawMarkersEnabled() || !valuesToHighlight()) { - return; - } - - for (int i = 0; i < mIndicesToHighlight.length; i++) { - - Highlight highlight = mIndicesToHighlight[i]; - - // When changing data sets and calling animation functions, sometimes an erroneous highlight is generated - // on the dataset that is removed. Null check to prevent crash - IDataSet set = mData.getDataSetByIndex(highlight.getDataSetIndex()); - if (set == null || !set.isVisible()) { - continue; - } - - Entry e = mData.getEntryForHighlight(highlight); - - // make sure entry not null before using it - if (e == null) { - continue; - } - - int entryIndex = set.getEntryIndex(e); - - if (entryIndex > set.getEntryCount() * mAnimator.getPhaseX()) { - continue; - } - - float[] pos = getMarkerPosition(highlight); - - // check bounds - if (!mViewPortHandler.isInBounds(pos[0], pos[1])) { - continue; - } - - // callbacks to update the content - if (!mMarkers.isEmpty()) { - int markerIndex = i % mMarkers.size(); - IMarker markerItem = mMarkers.get(markerIndex); - markerItem.refreshContent(e, highlight); - - // draw the marker - markerItem.draw(canvas, pos[0], pos[1]); - } - } - } - - /** - * Returns the actual position in pixels of the MarkerView for the given - * Highlight object. - */ - protected float[] getMarkerPosition(Highlight high) { - return new float[]{high.getDrawX(), high.getDrawY()}; - } - - /** - * Returns the animator responsible for animating chart values. - */ - public ChartAnimator getAnimator() { - return mAnimator; - } - - /** - * If set to true, chart continues to scroll after touch up default: true - */ - public boolean isDragDecelerationEnabled() { - return mDragDecelerationEnabled; - } - - /** - * If set to true, chart continues to scroll after touch up. Default: true. - */ - public void setDragDecelerationEnabled(boolean enabled) { - mDragDecelerationEnabled = enabled; - } - - /** - * Returns drag deceleration friction coefficient - */ - public float getDragDecelerationFrictionCoef() { - return mDragDecelerationFrictionCoef; - } - - /** - * Deceleration friction coefficient in [0 ; 1] interval, higher values - * indicate that speed will decrease slowly, for example if it set to 0, it - * will stop immediately. 1 is an invalid value, and will be converted to - * 0.999f automatically. - */ - public void setDragDecelerationFrictionCoef(float newValue) { - - if (newValue < 0.f) { - newValue = 0.f; - } - - if (newValue >= 1f) { - newValue = 0.999f; - } - - mDragDecelerationFrictionCoef = newValue; - } - - /** - * Animates the drawing / rendering of the chart on both x- and y-axis with - * the specified animation time. If animate(...) is called, no further - * calling of invalidate() is necessary to refresh the chart. ANIMATIONS - * ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER. - * - * @param easingX a custom easing function to be used on the animation phase - * @param easingY a custom easing function to be used on the animation phase - */ - public void animateXY(int durationMillisX, int durationMillisY, EasingFunction easingX, EasingFunction easingY) { - mAnimator.animateXY(durationMillisX, durationMillisY, easingX, easingY); - } - - /** - * Animates the drawing / rendering of the chart on both x- and y-axis with - * the specified animation time. If animate(...) is called, no further - * calling of invalidate() is necessary to refresh the chart. ANIMATIONS - * ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER. - * - * @param easing a custom easing function to be used on the animation phase - */ - public void animateXY(int durationMillisX, int durationMillisY, EasingFunction easing) { - mAnimator.animateXY(durationMillisX, durationMillisY, easing); - } - - /** - * Animates the rendering of the chart on the x-axis with the specified - * animation time. If animate(...) is called, no further calling of - * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR - * API LEVEL 11 (Android 3.0.x) AND HIGHER. - * - * @param easing a custom easing function to be used on the animation phase - */ - public void animateX(int durationMillis, EasingFunction easing) { - mAnimator.animateX(durationMillis, easing); - } - - /** - * Animates the rendering of the chart on the y-axis with the specified - * animation time. If animate(...) is called, no further calling of - * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR - * API LEVEL 11 (Android 3.0.x) AND HIGHER. - * - * @param easing a custom easing function to be used on the animation phase - */ - public void animateY(int durationMillis, EasingFunction easing) { - mAnimator.animateY(durationMillis, easing); - } - - /** - * Animates the rendering of the chart on the x-axis with the specified - * animation time. If animate(...) is called, no further calling of - * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR - * API LEVEL 11 (Android 3.0.x) AND HIGHER. - */ - public void animateX(int durationMillis) { - mAnimator.animateX(durationMillis); - } - - /** - * Animates the rendering of the chart on the y-axis with the specified - * animation time. If animate(...) is called, no further calling of - * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR - * API LEVEL 11 (Android 3.0.x) AND HIGHER. - */ - public void animateY(int durationMillis) { - mAnimator.animateY(durationMillis); - } - - /** - * Animates the drawing / rendering of the chart on both x- and y-axis with - * the specified animation time. If animate(...) is called, no further - * calling of invalidate() is necessary to refresh the chart. ANIMATIONS - * ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER. - */ - public void animateXY(int durationMillisX, int durationMillisY) { - mAnimator.animateXY(durationMillisX, durationMillisY); - } - - - /** - * Returns the object representing all x-labels, this method can be used to - * acquire the XAxis object and modify it (e.g. change the position of the - * labels, styling, etc.) - */ - public XAxis getXAxis() { - return mXAxis; - } - - /** - * Returns the default IValueFormatter that has been determined by the chart - * considering the provided minimum and maximum values. - */ - public IValueFormatter getDefaultValueFormatter() { - return mDefaultValueFormatter; - } - - /** - * set a selection listener for the chart - */ - public void setOnChartValueSelectedListener(OnChartValueSelectedListener l) { - this.mSelectionListener = l; - } - - /** - * Sets a gesture-listener for the chart for custom callbacks when executing - * gestures on the chart surface. - */ - public void setOnChartGestureListener(OnChartGestureListener l) { - this.mGestureListener = l; - } - - /** - * Returns the custom gesture listener. - */ - public OnChartGestureListener getOnChartGestureListener() { - return mGestureListener; - } - - /** - * returns the current y-max value across all DataSets - */ - public float getYMax() { - return mData.getYMax(); - } - - /** - * returns the current y-min value across all DataSets - */ - public float getYMin() { - return mData.getYMin(); - } - - @Override - public float getYChartMin() { - return mData.getYMin(); - } - - @Override - public float getYChartMax() { - return mData.getYMax(); - } - - @Override - public float getXChartMax() { - return mXAxis.mAxisMaximum; - } - - @Override - public float getXChartMin() { - return mXAxis.mAxisMinimum; - } - - @Override - public float getXRange() { - return mXAxis.mAxisRange; - } - - /** - * Returns a recyclable MPPointF instance. - * Returns the center point of the chart (the whole View) in pixels. - */ - public MPPointF getCenter() { - return MPPointF.Companion.getInstance(getWidth() / 2f, getHeight() / 2f); - } - - /** - * Returns a recyclable MPPointF instance. - * Returns the center of the chart taking offsets under consideration. - * (returns the center of the content rectangle) - */ - @Override - public MPPointF getCenterOffsets() { - return mViewPortHandler.getContentCenter(); - } - - /** - * Sets extra offsets (around the chart view) to be appended to the - * auto-calculated offsets. - */ - public void setExtraOffsets(float left, float top, float right, float bottom) { - setExtraLeftOffset(left); - setExtraTopOffset(top); - setExtraRightOffset(right); - setExtraBottomOffset(bottom); - } - - /** - * Set an extra offset to be appended to the viewport's top - */ - public void setExtraTopOffset(float offset) { - mExtraTopOffset = UtilsKtKt.convertDpToPixel(offset); - } - - /** - * @return the extra offset to be appended to the viewport's top - */ - public float getExtraTopOffset() { - return mExtraTopOffset; - } - - /** - * Set an extra offset to be appended to the viewport's right - */ - public void setExtraRightOffset(float offset) { - mExtraRightOffset = UtilsKtKt.convertDpToPixel(offset); - } - - /** - * @return the extra offset to be appended to the viewport's right - */ - public float getExtraRightOffset() { - return mExtraRightOffset; - } - - /** - * Set an extra offset to be appended to the viewport's bottom - */ - public void setExtraBottomOffset(float offset) { - mExtraBottomOffset = UtilsKtKt.convertDpToPixel(offset); - } - - /** - * @return the extra offset to be appended to the viewport's bottom - */ - public float getExtraBottomOffset() { - return mExtraBottomOffset; - } - - /** - * Set an extra offset to be appended to the viewport's left - */ - public void setExtraLeftOffset(float offset) { - mExtraLeftOffset = UtilsKtKt.convertDpToPixel(offset); - } - - /** - * @return the extra offset to be appended to the viewport's left - */ - public float getExtraLeftOffset() { - return mExtraLeftOffset; - } - - /** - * Set this to true to enable logcat outputs for the chart. Beware that - * logcat output decreases rendering performance. Default: disabled. - */ - public void setLogEnabled(boolean enabled) { - mLogEnabled = enabled; - } - - /** - * Returns true if log-output is enabled for the chart, fals if not. - */ - public boolean isLogEnabled() { - return mLogEnabled; - } - - /** - * Sets the text that informs the user that there is no data available with - * which to draw the chart. - */ - public void setNoDataText(String text) { - mNoDataText = text; - } - - /** - * Sets the color of the no data text. - */ - public void setNoDataTextColor(int color) { - mInfoPaint.setColor(color); - } - - /** - * Sets the typeface to be used for the no data text. - */ - public void setNoDataTextTypeface(Typeface tf) { - mInfoPaint.setTypeface(tf); - } - - /** - * alignment of the no data text - */ - public void setNoDataTextAlignment(Align align) { - mInfoPaint.setTextAlign(align); - } - - /** - * Set this to false to disable all gestures and touches on the chart, - * default: true - */ - public void setTouchEnabled(boolean enabled) { - this.mTouchEnabled = enabled; - } - - public void setMarkers(List marker) { - mMarkers = marker; - } - - /** - * sets the marker that is displayed when a value is clicked on the chart - */ - public void setMarker(IMarker marker) { - setMarkers(Collections.singletonList(marker)); - } - - /** - * returns the marker that is set as a marker view for the chart - */ - public List getMarker() { - return mMarkers; - } - - @Deprecated - public void setMarkerView(IMarker v) { - setMarker(v); - } - - @Deprecated - public List getMarkerView() { - return getMarker(); - } - - /** - * Sets a new Description object for the chart. - */ - public void setDescription(Description desc) { - this.mDescription = desc; - } - - /** - * Returns the Description object of the chart that is responsible for holding all information related - * to the description text that is displayed in the bottom right corner of the chart (by default). - */ - public Description getDescription() { - return mDescription; - } - - /** - * Returns the Legend object of the chart. This method can be used to get an - * instance of the legend in order to customize the automatically generated - * Legend. - */ - public Legend getLegend() { - return mLegend; - } - - /** - * Returns the renderer object responsible for rendering / drawing the - * Legend. - */ - public LegendRenderer getLegendRenderer() { - return mLegendRenderer; - } - - /** - * Returns the rectangle that defines the borders of the chart-value surface - * (into which the actual values are drawn). - */ - @Override - public RectF getContentRect() { - return mViewPortHandler.getContentRect(); - } - - /** - * disables intercept touchevents - */ - public void disableScroll() { - ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - } - - /** - * enables intercept touchevents - */ - public void enableScroll() { - ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(false); - } - } - - /** - * paint for the grid background (only line and barchart) - */ - public static final int PAINT_GRID_BACKGROUND = 4; - - /** - * paint for the info text that is displayed when there are no values in the - * chart - */ - public static final int PAINT_INFO = 7; - - /** - * paint for the description text in the bottom right corner - */ - public static final int PAINT_DESCRIPTION = 11; - - /** - * paint for the hole in the middle of the pie chart - */ - public static final int PAINT_HOLE = 13; - - /** - * paint for the text in the middle of the pie chart - */ - public static final int PAINT_CENTER_TEXT = 14; - - /** - * paint used for the legend - */ - public static final int PAINT_LEGEND_LABEL = 18; - - /** - * set a new paint object for the specified parameter in the chart e.g. - * Chart.PAINT_VALUES - * - * @param p the new paint object - * @param which Chart.PAINT_VALUES, Chart.PAINT_GRID, Chart.PAINT_VALUES, - * ... - */ - public void setPaint(Paint p, int which) { - - switch (which) { - case PAINT_INFO: - mInfoPaint = p; - break; - case PAINT_DESCRIPTION: - mDescPaint = p; - break; - } - } - - /** - * Returns the paint object associated with the provided constant. - * - * @param which e.g. Chart.PAINT_LEGEND_LABEL - */ - public Paint getPaint(int which) { - return switch (which) { - case PAINT_INFO -> mInfoPaint; - case PAINT_DESCRIPTION -> mDescPaint; - default -> null; - }; - - } - - @Deprecated - public boolean isDrawMarkerViewsEnabled() { - return isDrawMarkersEnabled(); - } - - @Deprecated - public void setDrawMarkerViews(boolean enabled) { - setDrawMarkers(enabled); - } - - /** - * returns true if drawing the marker is enabled when tapping on values - * (use the setMarker(IMarker marker) method to specify a marker) - */ - public boolean isDrawMarkersEnabled() { - return mDrawMarkers; - } - - /** - * Set this to true to draw a user specified marker when tapping on - * chart values (use the setMarker(IMarker marker) method to specify a - * marker). Default: true - */ - public void setDrawMarkers(boolean enabled) { - mDrawMarkers = enabled; - } - - /** - * Returns the ChartData object that has been set for the chart. - */ - public T getData() { - return mData; - } - - /** - * Returns the ViewPortHandler of the chart that is responsible for the - * content area of the chart and its offsets and dimensions. - */ - public ViewPortHandler getViewPortHandler() { - return mViewPortHandler; - } - - /** - * Returns the Renderer object the chart uses for drawing data. - */ - public DataRenderer getRenderer() { - return mRenderer; - } - - /** - * Sets a new DataRenderer object for the chart. - */ - public void setRenderer(DataRenderer renderer) { - - if (renderer != null) { - mRenderer = renderer; - } - } - - public IHighlighter getHighlighter() { - return mHighlighter; - } - - /** - * Sets a custom highligher object for the chart that handles / processes - * all highlight touch events performed on the chart-view. - */ - public void setHighlighter(ChartHighlighter highlighter) { - mHighlighter = highlighter; - } - - /** - * Returns a recyclable MPPointF instance. - */ - @Override - public MPPointF getCenterOfView() { - return getCenter(); - } - - /** - * Returns the bitmap that represents the chart. - */ - public Bitmap getChartBitmap() { - // Define a bitmap with the same size as the view - Bitmap returnedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565); - // Bind a canvas to it - Canvas canvas = new Canvas(returnedBitmap); - // Get the view's background - Drawable bgDrawable = getBackground(); - if (bgDrawable != null) - // has background drawable, then draw it on the canvas - { - bgDrawable.draw(canvas); - } else - // does not have background drawable, then draw white background on - // the canvas - { - canvas.drawColor(Color.WHITE); - } - // draw the view on the canvas - draw(canvas); - // return the bitmap - return returnedBitmap; - } - - /** - * Saves the current chart state with the given name to the given path on - * the sdcard leaving the path empty "" will put the saved file directly on - * the SD card chart is saved as a PNG image, example: - * saveToPath("myfilename", "foldername1/foldername2"); - * - * @param pathOnSD e.g. "folder1/folder2/folder3" - * @return returns true on success, false on error - */ - public boolean saveToPath(String title, String pathOnSD) { - return SaveUtils.INSTANCE.saveToPath(title, pathOnSD, getChartBitmap()); - } - - /** - * Saves the current state of the chart to the gallery as an image type. The - * compression must be set for JPEG only. 0 == maximum compression, 100 = low - * compression (high quality). NOTE: Needs permission WRITE_EXTERNAL_STORAGE - * - * @param fileName e.g. "my_image" - * @param subFolderPath e.g. "ChartPics" - * @param fileDescription e.g. "Chart details" - * @param format e.g. Bitmap.CompressFormat.PNG - * @param quality e.g. 50, min = 0, max = 100 - * @return returns true if saving was successful, false if not - */ - public boolean saveToGallery(String fileName, String subFolderPath, String fileDescription, Bitmap.CompressFormat format, int quality) { - return SaveUtils.INSTANCE.saveToGallery(fileName, subFolderPath, fileDescription, format, quality, getChartBitmap(), getContext()); - } - - /** - * Saves the current state of the chart to the gallery as a JPEG image. The - * filename and compression can be set. 0 == maximum compression, 100 = low - * compression (high quality). NOTE: Needs permission WRITE_EXTERNAL_STORAGE - * - * @param fileName e.g. "my_image" - * @param quality e.g. 50, min = 0, max = 100 - * @return returns true if saving was successful, false if not - */ - public boolean saveToGallery(String fileName, int quality) { - return saveToGallery(fileName, "", "AndroidChart-Library Save", Bitmap.CompressFormat.PNG, quality); - } - - /** - * Saves the current state of the chart to the gallery as a PNG image. - * NOTE: Needs permission WRITE_EXTERNAL_STORAGE - * - * @param fileName e.g. "my_image" - * @return returns true if saving was successful, false if not - */ - public boolean saveToGallery(String fileName) { - return saveToGallery(fileName, "", "AndroidChart-Library Save", Bitmap.CompressFormat.PNG, 40); - } - - /** - * tasks to be done after the view is setup - */ - protected ArrayList mJobs = new ArrayList<>(); - - public void removeViewportJob(Runnable job) { - mJobs.remove(job); - } - - public void clearAllViewportJobs() { - mJobs.clear(); - } - - /** - * Either posts a job immediately if the chart has already setup it's - * dimensions or adds the job to the execution queue. - */ - public void addViewportJob(Runnable job) { - - if (mViewPortHandler.hasChartDimens()) { - post(job); - } else { - mJobs.add(job); - } - } - - /** - * Returns all jobs that are scheduled to be executed after - * onSizeChanged(...). - */ - public ArrayList getJobs() { - return mJobs; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - - for (int i = 0; i < getChildCount(); i++) { - getChildAt(i).layout(left, top, right, bottom); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int size = (int) UtilsKtKt.convertDpToPixel(50f); - setMeasuredDimension(Math.max(getSuggestedMinimumWidth(), resolveSize(size, widthMeasureSpec)), Math.max(getSuggestedMinimumHeight(), resolveSize(size, heightMeasureSpec))); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - if (mLogEnabled) { - Log.i(LOG_TAG, "OnSizeChanged()"); - } - - if (w > 0 && h > 0 && w < 10000 && h < 10000) { - if (mLogEnabled) { - Log.i(LOG_TAG, "Setting chart dimens, width: " + w + ", height: " + h); - } - mViewPortHandler.setChartDimens(w, h); - } else { - if (mLogEnabled) { - Log.w(LOG_TAG, "*Avoiding* setting chart dimens! width: " + w + ", height: " + h); - } - } - - // This may cause the chart view to mutate properties affecting the view port -- - // lets do this before we try to run any pending jobs on the view port itself - notifyDataSetChanged(); - - for (Runnable r : mJobs) { - post(r); - } - - mJobs.clear(); - - super.onSizeChanged(w, h, oldw, oldh); - } - - /** - * Setting this to true will set the layer-type HARDWARE for the view, false - * will set layer-type SOFTWARE. - */ - public void setHardwareAccelerationEnabled(boolean enabled) { - - if (enabled) { - setLayerType(View.LAYER_TYPE_HARDWARE, null); - } else { - setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - - //Log.i(LOG_TAG, "Detaching..."); - - if (mUnbind) { - unbindDrawables(this); - } - } - - /** - * unbind flag - */ - private boolean mUnbind = false; - - /** - * Unbind all drawables to avoid memory leaks. - * Link: ... - */ - private void unbindDrawables(View view) { - - if (view.getBackground() != null) { - view.getBackground().setCallback(null); - } - if (view instanceof ViewGroup) { - for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { - unbindDrawables(((ViewGroup) view).getChildAt(i)); - } - ((ViewGroup) view).removeAllViews(); - } - } - - /** - * Set this to true to enable "unbinding" of drawables. When a View is detached - * from a window. This helps avoid memory leaks. - * Default: false - * Link: ... - */ - public void setUnbindEnabled(boolean enabled) { - this.mUnbind = enabled; - } - - // region accessibility - - /** - * - * @return accessibility description must be created for each chart - */ - public abstract String getAccessibilityDescription(); - - public String getAccessibilitySummaryDescription() { - return accessibilitySummaryDescription; - } - - public void setAccessibilitySummaryDescription(String accessibilitySummaryDescription) { - this.accessibilitySummaryDescription = accessibilitySummaryDescription; - } - - @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - - boolean completed = super.dispatchPopulateAccessibilityEvent(event); - Log.d(LOG_TAG, "Dispatch called for Chart and completed as " + completed); - - event.getText().add(getAccessibilityDescription()); - - // Add the user generated summary after the dynamic summary is complete. - if (!TextUtils.isEmpty(this.getAccessibilitySummaryDescription())) { - event.getText().add(this.getAccessibilitySummaryDescription()); - } - - return true; - } - - // endregion -} diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.kt new file mode 100644 index 000000000..804533b66 --- /dev/null +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.kt @@ -0,0 +1,1436 @@ +package com.github.mikephil.charting.charts + +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Bitmap.CompressFormat +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Paint.Align +import android.graphics.RectF +import android.graphics.Typeface +import android.text.TextUtils +import android.util.AttributeSet +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.view.accessibility.AccessibilityEvent +import com.github.mikephil.charting.animation.ChartAnimator +import com.github.mikephil.charting.animation.Easing.EasingFunction +import com.github.mikephil.charting.components.Description +import com.github.mikephil.charting.components.IMarker +import com.github.mikephil.charting.components.Legend +import com.github.mikephil.charting.components.XAxis +import com.github.mikephil.charting.data.ChartData +import com.github.mikephil.charting.data.Entry +import com.github.mikephil.charting.formatter.DefaultValueFormatter +import com.github.mikephil.charting.formatter.IValueFormatter +import com.github.mikephil.charting.highlight.ChartHighlighter +import com.github.mikephil.charting.highlight.Highlight +import com.github.mikephil.charting.highlight.IHighlighter +import com.github.mikephil.charting.interfaces.dataprovider.base.IBaseProvider +import com.github.mikephil.charting.interfaces.datasets.IDataSet +import com.github.mikephil.charting.listener.ChartTouchListener +import com.github.mikephil.charting.listener.OnChartGestureListener +import com.github.mikephil.charting.listener.OnChartValueSelectedListener +import com.github.mikephil.charting.renderer.DataRenderer +import com.github.mikephil.charting.renderer.LegendRenderer +import com.github.mikephil.charting.utils.MPPointF +import com.github.mikephil.charting.utils.MPPointF.Companion.getInstance +import com.github.mikephil.charting.utils.SaveUtils.saveToGallery +import com.github.mikephil.charting.utils.SaveUtils.saveToPath +import com.github.mikephil.charting.utils.Utils +import com.github.mikephil.charting.utils.ViewPortHandler +import com.github.mikephil.charting.utils.convertDpToPixel +import com.github.mikephil.charting.utils.getDecimals +import com.github.mikephil.charting.utils.initUtils +import kotlin.math.abs +import kotlin.math.max + +@Suppress("unused") +abstract class Chart>?> : ViewGroup, IBaseProvider { + /** + * Returns true if log-output is enabled for the chart, fals if not. + */ + /** + * Set this to true to enable logcat outputs for the chart. Beware that + * logcat output decreases rendering performance. Default: disabled. + */ + /** + * flag that indicates if logging is enabled or not + */ + var isLogEnabled: Boolean = false + + /** + * object that holds all data that was originally set for the chart, before + * it was modified or any filtering algorithms had been applied + */ + @JvmField + protected var mData: T? = null + + /** + * Returns true if values can be highlighted via tap gesture, false if not. + */ + /** + * Set this to false to prevent values from being highlighted by tap gesture. + * Values can still be highlighted via drag or programmatically. Default: true + */ + /** + * Flag that indicates if highlighting per tap (touch) is enabled + */ + var isHighlightPerTapEnabled: Boolean = true + + /** + * If set to true, chart continues to scroll after touch up default: true + */ + /** + * If set to true, chart continues to scroll after touch up. Default: true. + */ + /** + * If set to true, chart continues to scroll after touch up + */ + var isDragDecelerationEnabled: Boolean = true + + /** + * Deceleration friction coefficient in [0 ; 1] interval, higher values + * indicate that speed will decrease slowly, for example if it set to 0, it + * will stop immediately. 1 is an invalid value, and will be converted to + * 0.999f automatically. + */ + private var mDragDecelerationFrictionCoef = 0.9f + + /** + * default value-formatter, number of digits depends on provided chart-data + */ + protected var mDefaultValueFormatter: DefaultValueFormatter = DefaultValueFormatter(0) + + /** + * paint object used for drawing the description text in the bottom right + * corner of the chart + */ + protected var mDescPaint: Paint? = null + + /** + * paint object for drawing the information text when there are no values in + * the chart + */ + protected var mInfoPaint: Paint? = null + + /** + * the object representing the labels on the x-axis + */ + @JvmField + protected var mXAxis: XAxis = XAxis() + + /** + * if true, touch gestures are enabled on the chart + */ + @JvmField + protected var mTouchEnabled: Boolean = true + + /** + * Returns the Description object of the chart that is responsible for holding all information related + * to the description text that is displayed in the bottom right corner of the chart (by default). + */ + /** + * Sets a new Description object for the chart. + */ + /** + * the object responsible for representing the description text + */ + var description: Description? = null + + /** + * Returns the Legend object of the chart. This method can be used to get an + * instance of the legend in order to customize the automatically generated + * Legend. + */ + /** + * the legend object containing all data associated with the legend + */ + var legend: Legend? = null + protected set + + /** + * listener that is called when a value on the chart is selected + */ + protected var mSelectionListener: OnChartValueSelectedListener? = null + + @JvmField + protected var mChartTouchListener: ChartTouchListener<*>? = null + + /** + * text that is displayed when the chart is empty + */ + private var mNoDataText = "No chart data available." + + /** + * Returns the custom gesture listener. + */ + /** + * Sets a gesture-listener for the chart for custom callbacks when executing + * gestures on the chart surface. + */ + /** + * Gesture listener for custom callbacks when making gestures on the chart. + */ + var onChartGestureListener: OnChartGestureListener? = null + + /** + * Returns the renderer object responsible for rendering / drawing the + * Legend. + */ + var legendRenderer: LegendRenderer? = null + protected set + + /** + * object responsible for rendering the data + */ + @JvmField + protected var mRenderer: DataRenderer? = null + + var highlighter: IHighlighter? = null + protected set + + /** + * Returns the ViewPortHandler of the chart that is responsible for the + * content area of the chart and its offsets and dimensions. + */ + /** + * object that manages the bounds and drawing constraints of the chart + */ + var viewPortHandler: ViewPortHandler = ViewPortHandler() + protected set + + /** + * object responsible for animations + */ + protected var mAnimator: ChartAnimator = ChartAnimator() + + /** + * Extra offsets to be appended to the viewport + */ + private var mExtraTopOffset = 0f + private var mExtraRightOffset = 0f + private var mExtraBottomOffset = 0f + private var mExtraLeftOffset = 0f + + /** + * Additional data on top of dynamically generated description. This can be set by the user. + */ + var accessibilitySummaryDescription: String? = "" + + /** + * default constructor for initialization in code + */ + constructor(context: Context?) : super(context) { + init() + } + + /** + * constructor for initialization in xml + */ + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { + init() + } + + /** + * even more awesome constructor + */ + constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) { + init() + } + + /** + * initialize all paints and stuff + */ + protected open fun init() { + setWillNotDraw(false) + + // setLayerType(View.LAYER_TYPE_HARDWARE, null); + mAnimator = ChartAnimator { animation: ValueAnimator? -> + // ViewCompat.postInvalidateOnAnimation(Chart.this); + postInvalidate() + } + + // initialize the utils + Utils.init(context) + context.initUtils() + mMaxHighlightDistance = 500f.convertDpToPixel() + + this.description = Description() + this.legend = Legend() + + this.legendRenderer = LegendRenderer(this.viewPortHandler, this.legend!!) + + mXAxis = XAxis() + + mDescPaint = Paint(Paint.ANTI_ALIAS_FLAG) + + mInfoPaint = Paint(Paint.ANTI_ALIAS_FLAG) + mInfoPaint!!.color = Color.rgb(247, 189, 51) // orange + mInfoPaint!!.textAlign = Align.CENTER + mInfoPaint!!.textSize = 12f.convertDpToPixel() + + if (this.isLogEnabled) { + Log.i("", "Chart.init()") + + // enable being detected by ScreenReader + setFocusable(true) + } + } + + // public void initWithDummyData() { + // ColorTemplate template = new ColorTemplate(); + // template.addColorsForDataSets(ColorTemplate.COLORFUL_COLORS, + // getContext()); + // + // setColorTemplate(template); + // setDrawYValues(false); + // + // ArrayList xVals = new ArrayList(); + // Calendar calendar = Calendar.getInstance(); + // for (int i = 0; i < 12; i++) { + // xVals.add(calendar.getDisplayName(Calendar.MONTH, Calendar.SHORT, + // Locale.getDefault())); + // } + // + // ArrayList dataSets = new ArrayList(); + // for (int i = 0; i < 3; i++) { + // + // ArrayList yVals = new ArrayList(); + // + // for (int j = 0; j < 12; j++) { + // float val = (float) (Math.random() * 100); + // yVals.add(new Entry(val, j)); + // } + // + // DataSet set = new DataSet(yVals, "DataSet " + i); + // dataSets.add(set); // add the datasets + // } + // // create a data object with the datasets + // ChartData data = new ChartData(xVals, dataSets); + // setData(data); + // invalidate(); + // } + /** + * Sets a new data object for the chart. The data object contains all values + * and information needed for displaying. + */ + open fun setData(data: T?) { + mData = data + mOffsetsCalculated = false + + if (data == null) { + return + } + + // calculate how many digits are needed + setupDefaultFormatter(data.yMin, data.yMax) + + for (set in mData!!.dataSets!!) { + if (set.needsFormatter() || set.valueFormatter === mDefaultValueFormatter) { + set.valueFormatter = mDefaultValueFormatter + } + } + + // let the chart know there is new data + notifyDataSetChanged() + + if (this.isLogEnabled) { + Log.i(LOG_TAG, "Data is set.") + } + } + + /** + * Clears the chart from all data (sets it to null) and refreshes it (by + * calling invalidate()). + */ + fun clear() { + mData = null + mOffsetsCalculated = false + this.highlighted = null + mChartTouchListener!!.setLastHighlighted(null) + invalidate() + } + + /** + * Removes all DataSets (and thereby Entries) from the chart. Does not set the data object to null. Also refreshes the + * chart by calling invalidate(). + */ + fun clearValues() { + mData!!.clearValues() + invalidate() + } + + val isEmpty: Boolean + /** + * Returns true if the chart is empty (meaning it's data object is either + * null or contains no entries). + */ + get() { + return if (mData == null) { + true + } else { + mData!!.entryCount <= 0 + } + } + + /** + * Lets the chart know its underlying data has changed and performs all + * necessary recalculations. It is crucial that this method is called + * everytime data is changed dynamically. Not calling this method can lead + * to crashes or unexpected behaviour. + */ + abstract fun notifyDataSetChanged() + + /** + * Calculates the offsets of the chart to the border depending on the + * position of an eventual legend or depending on the length of the y-axis + * and x-axis labels and their position + */ + protected abstract fun calculateOffsets() + + /** + * Calculates the y-min and y-max value and the y-delta and x-delta value + */ + protected abstract fun calcMinMax() + + /** + * Calculates the required number of digits for the values that might be + * drawn in the chart (if enabled), and creates the default-value-formatter + */ + protected fun setupDefaultFormatter(min: Float, max: Float) { + + val reference: Float = if (mData == null || mData!!.entryCount < 2) { + max(abs(min), abs(max)) + } else { + abs(max - min) + } + + val digits = reference.getDecimals() + + // setup the formatter with a new number of digits + mDefaultValueFormatter.setup(digits) + } + + /** + * flag that indicates if offsets calculation has already been done or not + */ + private var mOffsetsCalculated = false + + override fun onDraw(canvas: Canvas) { + // super.onDraw(canvas); + + if (mData == null) { + val hasText = !TextUtils.isEmpty(mNoDataText) + + if (hasText) { + val pt = this.center + + when (mInfoPaint!!.textAlign) { + Align.LEFT -> { + pt.x = 0F + canvas.drawText(mNoDataText, pt.x, pt.y, mInfoPaint!!) + } + + Align.RIGHT -> { + pt.x *= 2.0f + canvas.drawText(mNoDataText, pt.x, pt.y, mInfoPaint!!) + } + + else -> canvas.drawText(mNoDataText, pt.x, pt.y, mInfoPaint!!) + } + } + + return + } + + if (!mOffsetsCalculated) { + calculateOffsets() + mOffsetsCalculated = true + } + } + + /** + * Draws the description text in the bottom right corner of the chart (per default) + */ + protected fun drawDescription(c: Canvas) { + // check if description should be drawn + + if (this.description != null && description!!.isEnabled) { + val position = description!!.position + + mDescPaint!!.typeface = description!!.typeface + mDescPaint!!.textSize = description!!.textSize + mDescPaint!!.color = description!!.textColor + mDescPaint!!.textAlign = description!!.textAlign + + val x: Float + val y: Float + + // if no position specified, draw on default position + if (position == null) { + x = width - viewPortHandler.offsetRight() - description!!.xOffset + y = height - viewPortHandler.offsetBottom() - description!!.yOffset + } else { + x = position.x + y = position.y + } + + c.drawText(description!!.text!!, x, y, mDescPaint!!) + } + } + + /** + * Returns the array of currently highlighted values. This might a null or + * empty array if nothing is highlighted. + */ + /** + * array of Highlight objects that reference the highlighted slices in the + * chart + */ + var highlighted: Array? = null + protected set + + /** + * The maximum distance in dp away from an entry causing it to highlight. + */ + protected var mMaxHighlightDistance: Float = 0f + + override var maxHighlightDistance: Float + get() = mMaxHighlightDistance + /** + * Sets the maximum distance in screen dp a touch can be away from an entry to cause it to get highlighted. + * Default: 500dp + */ + set(distDp) { + mMaxHighlightDistance = distDp.convertDpToPixel() + } + + /** + * Returns true if there are values to highlight, false if there are no + * values to highlight. Checks if the highlight array is null, has a length + * of zero or if the first object is null. + */ + fun valuesToHighlight(): Boolean { + return this.highlighted != null && highlighted!!.isNotEmpty() + } + + /** + * Sets the last highlighted value for the touch listener. + */ + protected fun setLastHighlighted(highs: Array?) { + if (highs == null || highs.isEmpty()) { + mChartTouchListener!!.setLastHighlighted(null) + } else { + mChartTouchListener!!.setLastHighlighted(highs[0]) + } + } + + /** + * Highlights the values at the given indices in the given DataSets. Provide + * null or an empty array to undo all highlighting. This should be used to + * programmatically highlight values. + * This method *will not* call the listener. + */ + fun highlightValues(highs: Array?) { + // set the indices to highlight + + this.highlighted = highs + + setLastHighlighted(highs) + + // redraw the chart + invalidate() + } + + fun highlightValues(highs: MutableList, markers: MutableList) { + require(highs.size == markers.size) { "Markers and highs must be mutually corresponding. High size = " + highs.size + " Markers size = " + markers.size } + setMarkers(markers) + highlightValues(highs.toTypedArray()) + } + + /** + * Highlights any y-value at the given x-value in the given DataSet. + * Provide -1 as the dataSetIndex to undo all highlighting. + * This method will call the listener. + * * @param x The x-value to highlight + * + * @param dataSetIndex The dataset index to search in + * @param dataIndex The data index to search in (only used in CombinedChartView currently) + */ + open fun getHighlightValue(x: Float, dataSetIndex: Int, dataIndex: Int) { + highlightValue(x, dataSetIndex, dataIndex, true) + } + + /** + * Highlights any y-value at the given x-value in the given DataSet. + * Provide -1 as the dataSetIndex to undo all highlighting. + * + * @param x The x-value to highlight + * @param dataSetIndex The dataset index to search in + * @param dataIndex The data index to search in (only used in CombinedChartView currently) + * @param callListener Should the listener be called for this change + */ + @JvmOverloads + fun highlightValue(x: Float, dataSetIndex: Int, dataIndex: Int = -1, callListener: Boolean = true) { + highlightValue(x, Float.NaN, dataSetIndex, dataIndex, callListener) + } + + /** + * Highlights any y-value at the given x-value in the given DataSet. + * Provide -1 as the dataSetIndex to undo all highlighting. + * + * @param x The x-value to highlight + * @param dataSetIndex The dataset index to search in + * @param callListener Should the listener be called for this change + */ + fun highlightValue(x: Float, dataSetIndex: Int, callListener: Boolean) { + highlightValue(x, Float.NaN, dataSetIndex, -1, callListener) + } + + /** + * Highlights the value at the given x-value and y-value in the given DataSet. + * Provide -1 as the dataSetIndex to undo all highlighting. + * This method will call the listener. + * + * @param x The x-value to highlight + * @param y The y-value to highlight. Supply `NaN` for "any" + * @param dataSetIndex The dataset index to search in + * @param dataIndex The data index to search in (only used in CombinedChartView currently) + */ + @JvmOverloads + fun highlightValue(x: Float, y: Float, dataSetIndex: Int, dataIndex: Int = -1, callListener: Boolean = true) { + if (dataSetIndex < 0 || dataSetIndex >= mData!!.dataSetCount) { + highlightValue(null, callListener) + } else { + highlightValue(Highlight(x, y, dataSetIndex, dataIndex), callListener) + } + } + + /** + * Highlights any y-value at the given x-value in the given DataSet. + * Provide -1 as the dataSetIndex to undo all highlighting. + * + * @param x The x-value to highlight + * @param y The y-value to highlight. Supply `NaN` for "any" + * @param dataSetIndex The dataset index to search in + * @param callListener Should the listener be called for this change + */ + fun highlightValue(x: Float, y: Float, dataSetIndex: Int, callListener: Boolean) { + highlightValue(x, y, dataSetIndex, -1, callListener) + } + + /** + * Highlights the values represented by the provided Highlight object + * This method *will not* call the listener. + * + * @param highlight contains information about which entry should be highlighted + */ + fun highlightValue(highlight: Highlight?) { + highlightValue(highlight, false) + } + + /** + * Highlights the value selected by touch gesture. Unlike + * highlightValues(...), this generates a callback to the + * OnChartValueSelectedListener. + * + * @param high - the highlight object + * @param callListener - call the listener + */ + fun highlightValue(high: Highlight?, callListener: Boolean) { + var high = high + var entry: Entry? = null + + if (high == null) { + this.highlighted = null + } else { + if (this.isLogEnabled) { + Log.i(LOG_TAG, "Highlighted: $high") + } + + entry = mData!!.getEntryForHighlight(high) + if (entry == null) { + this.highlighted = null + high = null + } else { + // set the indices to highlight + + this.highlighted = arrayOf(high) + } + } + + setLastHighlighted(this.highlighted) + + if (callListener && mSelectionListener != null) { + if (!valuesToHighlight()) { + mSelectionListener!!.onNothingSelected() + } else { + // notify the listener + mSelectionListener!!.onValueSelected(entry!!, high!!) + } + } + + // redraw the chart + invalidate() + } + + /** + * Returns the Highlight object (contains x-index and DataSet index) of the + * selected value at the given touch point inside the Line-, Scatter-, or + * CandleStick-Chart. + */ + open fun getHighlightByTouchPoint(x: Float, y: Float): Highlight? { + if (mData == null) { + Log.e(LOG_TAG, "Can't select by touch. No data set.") + return null + } else { + return this.highlighter!!.getHighlight(x, y) + } + } + + var onTouchListener: ChartTouchListener<*> + /** + * Returns an instance of the currently active touch listener. + */ + get() = mChartTouchListener!! + /** + * Set a new (e.g. custom) ChartTouchListener NOTE: make sure to + * setTouchEnabled(true); if you need touch gestures on the chart + */ + set(touchListener) { + this.mChartTouchListener = touchListener + } + + /** + * returns true if drawing the marker is enabled when tapping on values + * (use the setMarker(IMarker marker) method to specify a marker) + */ + /** + * if set to true, the marker view is drawn when a value is clicked + */ + var isDrawMarkersEnabled: Boolean = true + protected set + + /** + * returns the marker that is set as a marker view for the chart + */ + /** + * the view that represents the marker + */ + var marker: MutableList = ArrayList() + protected set + + /** + * draws all MarkerViews on the highlighted positions + */ + protected open fun drawMarkers(canvas: Canvas) { + // if there is no marker view or drawing marker is disabled + + if (!this.isDrawMarkersEnabled || !valuesToHighlight()) { + return + } + + for (i in highlighted!!.indices) { + val highlight = this.highlighted!![i] + + // When changing data sets and calling animation functions, sometimes an erroneous highlight is generated + // on the dataset that is removed. Null check to prevent crash + val dataset: IDataSet<*>? = mData!!.getDataSetByIndex(highlight.dataSetIndex) + if (dataset == null || !dataset.isVisible) { + continue + } + + val e = mData!!.getEntryForHighlight(highlight) ?: continue + + // make sure entry not null before using it + + // Cast to non-star-projected type to allow calling getEntryIndex + @Suppress("UNCHECKED_CAST") + val set = dataset as IDataSet + val entryIndex = set.getEntryIndex(e) + + if (entryIndex > set.entryCount * mAnimator.phaseX) { + continue + } + + val pos = getMarkerPosition(highlight) + + // check bounds + if (!viewPortHandler.isInBounds(pos[0], pos[1])) { + continue + } + + // callbacks to update the content + if (!marker.isEmpty()) { + val markerIndex = i % marker.size + val markerItem = marker[markerIndex] + markerItem.refreshContent(e, highlight) + + // draw the marker + markerItem.draw(canvas, pos[0], pos[1]) + } + } + } + + /** + * Returns the actual position in pixels of the MarkerView for the given + * Highlight object. + */ + protected open fun getMarkerPosition(high: Highlight): FloatArray { + return floatArrayOf(high.drawX, high.drawY) + } + + val animator: ChartAnimator + /** + * Returns the animator responsible for animating chart values. + */ + get() = mAnimator + + var dragDecelerationFrictionCoef: Float + /** + * Returns drag deceleration friction coefficient + */ + get() = mDragDecelerationFrictionCoef + /** + * Deceleration friction coefficient in [0 ; 1] interval, higher values + * indicate that speed will decrease slowly, for example if it set to 0, it + * will stop immediately. 1 is an invalid value, and will be converted to + * 0.999f automatically. + */ + set(newValue) { + var newValue = newValue + if (newValue < 0f) { + newValue = 0f + } + + if (newValue >= 1f) { + newValue = 0.999f + } + + mDragDecelerationFrictionCoef = newValue + } + + /** + * Animates the drawing / rendering of the chart on both x- and y-axis with + * the specified animation time. If animate(...) is called, no further + * calling of invalidate() is necessary to refresh the chart. ANIMATIONS + * ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER. + * + * @param easingX a custom easing function to be used on the animation phase + * @param easingY a custom easing function to be used on the animation phase + */ + fun animateXY(durationMillisX: Int, durationMillisY: Int, easingX: EasingFunction?, easingY: EasingFunction?) { + mAnimator.animateXY(durationMillisX, durationMillisY, easingX, easingY) + } + + /** + * Animates the drawing / rendering of the chart on both x- and y-axis with + * the specified animation time. If animate(...) is called, no further + * calling of invalidate() is necessary to refresh the chart. ANIMATIONS + * ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER. + * + * @param easing a custom easing function to be used on the animation phase + */ + fun animateXY(durationMillisX: Int, durationMillisY: Int, easing: EasingFunction?) { + mAnimator.animateXY(durationMillisX, durationMillisY, easing) + } + + /** + * Animates the rendering of the chart on the x-axis with the specified + * animation time. If animate(...) is called, no further calling of + * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR + * API LEVEL 11 (Android 3.0.x) AND HIGHER. + * + * @param easing a custom easing function to be used on the animation phase + */ + fun animateX(durationMillis: Int, easing: EasingFunction?) { + mAnimator.animateX(durationMillis, easing) + } + + /** + * Animates the rendering of the chart on the y-axis with the specified + * animation time. If animate(...) is called, no further calling of + * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR + * API LEVEL 11 (Android 3.0.x) AND HIGHER. + * + * @param easing a custom easing function to be used on the animation phase + */ + fun animateY(durationMillis: Int, easing: EasingFunction?) { + mAnimator.animateY(durationMillis, easing) + } + + /** + * Animates the rendering of the chart on the x-axis with the specified + * animation time. If animate(...) is called, no further calling of + * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR + * API LEVEL 11 (Android 3.0.x) AND HIGHER. + */ + fun animateX(durationMillis: Int) { + mAnimator.animateX(durationMillis) + } + + /** + * Animates the rendering of the chart on the y-axis with the specified + * animation time. If animate(...) is called, no further calling of + * invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR + * API LEVEL 11 (Android 3.0.x) AND HIGHER. + */ + fun animateY(durationMillis: Int) { + mAnimator.animateY(durationMillis) + } + + /** + * Animates the drawing / rendering of the chart on both x- and y-axis with + * the specified animation time. If animate(...) is called, no further + * calling of invalidate() is necessary to refresh the chart. ANIMATIONS + * ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER. + */ + fun animateXY(durationMillisX: Int, durationMillisY: Int) { + mAnimator.animateXY(durationMillisX, durationMillisY) + } + + + open val xAxis: XAxis + /** + * Returns the object representing all x-labels, this method can be used to + * acquire the XAxis object and modify it (e.g. change the position of the + * labels, styling, etc.) + */ + get() = mXAxis + + override val defaultValueFormatter: IValueFormatter + /** + * Returns the default IValueFormatter that has been determined by the chart + * considering the provided minimum and maximum values. + */ + get() = mDefaultValueFormatter + + /** + * set a selection listener for the chart + */ + fun setOnChartValueSelectedListener(l: OnChartValueSelectedListener?) { + this.mSelectionListener = l + } + + val yMax: Float + /** + * returns the current y-max value across all DataSets + */ + get() = mData!!.yMax + + val yMin: Float + /** + * returns the current y-min value across all DataSets + */ + get() = mData!!.yMin + + override val yChartMin: Float + get() = mData!!.yMin + + override val yChartMax: Float + get() = mData!!.yMax + + override val xChartMax: Float + get() = mXAxis.mAxisMaximum + + override val xChartMin: Float + get() = mXAxis.mAxisMinimum + + override val xRange: Float + get() = mXAxis.mAxisRange + + val center: MPPointF + /** + * Returns a recyclable MPPointF instance. + * Returns the center point of the chart (the whole View) in pixels. + */ + get() = getInstance(width / 2f, height / 2f) + + override val centerOffsets: MPPointF + /** + * Returns a recyclable MPPointF instance. + * Returns the center of the chart taking offsets under consideration. + * (returns the center of the content rectangle) + */ + get() = viewPortHandler.contentCenter + + /** + * Sets extra offsets (around the chart view) to be appended to the + * auto-calculated offsets. + */ + fun setExtraOffsets(left: Float, top: Float, right: Float, bottom: Float) { + this.extraLeftOffset = left + this.extraTopOffset = top + this.extraRightOffset = right + this.extraBottomOffset = bottom + } + + var extraTopOffset: Float + /** + * @return the extra offset to be appended to the viewport's top + */ + get() = mExtraTopOffset + /** + * Set an extra offset to be appended to the viewport's top + */ + set(offset) { + mExtraTopOffset = offset.convertDpToPixel() + } + + var extraRightOffset: Float + /** + * @return the extra offset to be appended to the viewport's right + */ + get() = mExtraRightOffset + /** + * Set an extra offset to be appended to the viewport's right + */ + set(offset) { + mExtraRightOffset = offset.convertDpToPixel() + } + + var extraBottomOffset: Float + /** + * @return the extra offset to be appended to the viewport's bottom + */ + get() = mExtraBottomOffset + /** + * Set an extra offset to be appended to the viewport's bottom + */ + set(offset) { + mExtraBottomOffset = offset.convertDpToPixel() + } + + var extraLeftOffset: Float + /** + * @return the extra offset to be appended to the viewport's left + */ + get() = mExtraLeftOffset + /** + * Set an extra offset to be appended to the viewport's left + */ + set(offset) { + mExtraLeftOffset = offset.convertDpToPixel() + } + + /** + * Sets the text that informs the user that there is no data available with + * which to draw the chart. + */ + fun setNoDataText(text: String) { + mNoDataText = text + } + + /** + * Sets the color of the no data text. + */ + fun setNoDataTextColor(color: Int) { + mInfoPaint!!.color = color + } + + /** + * Sets the typeface to be used for the no data text. + */ + fun setNoDataTextTypeface(tf: Typeface?) { + mInfoPaint!!.typeface = tf + } + + /** + * alignment of the no data text + */ + fun setNoDataTextAlignment(align: Align?) { + mInfoPaint!!.textAlign = align + } + + /** + * Set this to false to disable all gestures and touches on the chart, + * default: true + */ + fun setTouchEnabled(enabled: Boolean) { + this.mTouchEnabled = enabled + } + + fun setMarkers(marker: MutableList) { + this.marker = marker + } + + /** + * sets the marker that is displayed when a value is clicked on the chart + */ + fun setMarker(marker: IMarker) { + setMarkers(mutableListOf(marker)) + } + + @Deprecated("") + fun setMarkerView(v: IMarker) { + setMarker(v) + } + + @get:Deprecated("") + val markerView: MutableList + get() = this.marker + + override val contentRect: RectF + /** + * Returns the rectangle that defines the borders of the chart-value surface + * (into which the actual values are drawn). + */ + get() = viewPortHandler.contentRect + + /** + * disables intercept touch events + */ + fun disableScroll() { + val parent = getParent() + parent?.requestDisallowInterceptTouchEvent(true) + } + + /** + * enables intercept touch events + */ + fun enableScroll() { + val parent = getParent() + parent?.requestDisallowInterceptTouchEvent(false) + } + + /** + * set a new paint object for the specified parameter in the chart e.g. + * Chart.PAINT_VALUES + * + * @param p the new paint object + * @param which Chart.PAINT_VALUES, Chart.PAINT_GRID, Chart.PAINT_VALUES, + * ... + */ + open fun setPaint(p: Paint, which: Int) { + when (which) { + PAINT_INFO -> mInfoPaint = p + PAINT_DESCRIPTION -> mDescPaint = p + } + } + + /** + * Returns the paint object associated with the provided constant. + * + * @param which e.g. Chart.PAINT_LEGEND_LABEL + */ + open fun getPaint(which: Int): Paint? { + return when (which) { + PAINT_INFO -> mInfoPaint + PAINT_DESCRIPTION -> mDescPaint + else -> null + } + } + + @get:Deprecated("") + val isDrawMarkerViewsEnabled: Boolean + get() = this.isDrawMarkersEnabled + + @Deprecated("") + fun setDrawMarkerViews(enabled: Boolean) { + setDrawMarkers(enabled) + } + + /** + * Set this to true to draw a user specified marker when tapping on + * chart values (use the setMarker(IMarker marker) method to specify a + * marker). Default: true + */ + fun setDrawMarkers(enabled: Boolean) { + this.isDrawMarkersEnabled = enabled + } + + /** + * Returns the ChartData object that has been set for the chart. + */ + override fun getData(): T? { + return mData + } + + var renderer: DataRenderer? + /** + * Returns the Renderer object the chart uses for drawing data. + */ + get() = mRenderer + /** + * Sets a new DataRenderer object for the chart. + */ + set(renderer) { + if (renderer != null) { + mRenderer = renderer + } + } + + /** + * Sets a custom highlighter object for the chart that handles / processes + * all highlight touch events performed on the chart-view. + */ + fun setHighlighter(highlighter: ChartHighlighter<*>?) { + this.highlighter = highlighter + } + + override val centerOfView: MPPointF + /** + * Returns a recyclable MPPointF instance. + */ + get() = this.center + + val chartBitmap: Bitmap + /** + * Returns the bitmap that represents the chart. + */ + get() { + // Define a bitmap with the same size as the view + val returnedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) + // Bind a canvas to it + val canvas = Canvas(returnedBitmap) + // Get the view's background + val bgDrawable = background + if (bgDrawable != null) // has background drawable, then draw it on the canvas + { + bgDrawable.draw(canvas) + } else // does not have background drawable, then draw white background on + // the canvas + { + canvas.drawColor(Color.WHITE) + } + // draw the view on the canvas + draw(canvas) + // return the bitmap + return returnedBitmap + } + + /** + * Saves the current chart state with the given name to the given path on + * the sdcard leaving the path empty "" will put the saved file directly on + * the SD card chart is saved as a PNG image, example: + * saveToPath("myFilename", "folderNameA/folderNameB"); + * + * @param pathOnSD e.g. "folder1/folder2/folder3" + * @return returns true on success, false on error + */ + fun saveToPath(title: String?, pathOnSD: String?): Boolean { + return saveToPath(title, pathOnSD, this.chartBitmap) + } + + /** + * Saves the current state of the chart to the gallery as an image type. The + * compression must be set for JPEG only. 0 == maximum compression, 100 = low + * compression (high quality). NOTE: Needs permission WRITE_EXTERNAL_STORAGE + * + * @param fileName e.g. "my_image" + * @param subFolderPath e.g. "ChartPics" + * @param fileDescription e.g. "Chart details" + * @param format e.g. Bitmap.CompressFormat.PNG + * @param quality e.g. 50, min = 0, max = 100 + * @return returns true if saving was successful, false if not + */ + @JvmOverloads + fun saveToGallery( + fileName: String, + subFolderPath: String? = "", + fileDescription: String? = "AndroidChart-Library Save", + format: CompressFormat = CompressFormat.PNG, + quality: Int = 40 + ): Boolean { + return saveToGallery(fileName, subFolderPath, fileDescription, format, quality, this.chartBitmap, context) + } + + /** + * Saves the current state of the chart to the gallery as a JPEG image. The + * filename and compression can be set. 0 == maximum compression, 100 = low + * compression (high quality). NOTE: Needs permission WRITE_EXTERNAL_STORAGE + * + * @param fileName e.g. "my_image" + * @param quality e.g. 50, min = 0, max = 100 + * @return returns true if saving was successful, false if not + */ + fun saveToGallery(fileName: String, quality: Int): Boolean { + return saveToGallery(fileName, "", "AndroidChart-Library Save", CompressFormat.PNG, quality) + } + + /** + * Returns all jobs that are scheduled to be executed after + * onSizeChanged(...). + */ + /** + * tasks to be done after the view is setup + */ + var jobs: ArrayList = ArrayList() + protected set + + fun removeViewportJob(job: Runnable?) { + jobs.remove(job) + } + + fun clearAllViewportJobs() { + jobs.clear() + } + + /** + * Either posts a job immediately if the chart has already setup it's + * dimensions or adds the job to the execution queue. + */ + fun addViewportJob(job: Runnable?) { + if (viewPortHandler.hasChartDimens()) { + post(job) + } else { + jobs.add(job) + } + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + for (i in 0.. 0 && h > 0 && w < 10000 && h < 10000) { + if (this.isLogEnabled) { + Log.i(LOG_TAG, "Setting chart dimens, width: $w, height: $h") + } + viewPortHandler.setChartDimens(w.toFloat(), h.toFloat()) + } else { + if (this.isLogEnabled) { + Log.w(LOG_TAG, "*Avoiding* setting chart dimens! width: $w, height: $h") + } + } + + // This may cause the chart view to mutate properties affecting the view port -- + // lets do this before we try to run any pending jobs on the view port itself + notifyDataSetChanged() + + for (r in this.jobs) { + post(r) + } + + jobs.clear() + + super.onSizeChanged(w, h, oldw, oldh) + } + + /** + * Setting this to true will set the layer-type HARDWARE for the view, false + * will set layer-type SOFTWARE. + */ + fun setHardwareAccelerationEnabled(enabled: Boolean) { + if (enabled) { + setLayerType(LAYER_TYPE_HARDWARE, null) + } else { + setLayerType(LAYER_TYPE_SOFTWARE, null) + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + + //Log.i(LOG_TAG, "Detaching..."); + if (mUnbind) { + unbindDrawables(this) + } + } + + /** + * unbind flag + */ + private var mUnbind = false + + /** + * Unbind all drawables to avoid memory leaks. + * Link: [...](http://stackoverflow.com/a/6779164/1590502) + */ + private fun unbindDrawables(view: View) { + if (view.background != null) { + view.background.callback = null + } + if (view is ViewGroup) { + for (i in 0.. and completed as $completed") + + event.text.add(this.accessibilityDescription) + + // Add the user generated summary after the dynamic summary is complete. + if (!TextUtils.isEmpty(this.accessibilitySummaryDescription)) { + event.text.add(this.accessibilitySummaryDescription) + } + + return true + } // endregion + + companion object { + const val LOG_TAG: String = "AndroidChart" + + /** + * paint for the grid background (only line and barchart) + */ + const val PAINT_GRID_BACKGROUND: Int = 4 + + /** + * paint for the info text that is displayed when there are no values in the + * chart + */ + const val PAINT_INFO: Int = 7 + + /** + * paint for the description text in the bottom right corner + */ + const val PAINT_DESCRIPTION: Int = 11 + + /** + * paint for the hole in the middle of the pie chart + */ + const val PAINT_HOLE: Int = 13 + + /** + * paint for the text in the middle of the pie chart + */ + const val PAINT_CENTER_TEXT: Int = 14 + + /** + * paint used for the legend + */ + const val PAINT_LEGEND_LABEL: Int = 18 + } +} diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CombinedChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CombinedChart.kt index 0326b53a8..d257241de 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CombinedChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/CombinedChart.kt @@ -64,7 +64,7 @@ open class CombinedChart : BarLineChartBase, CombinedDataProvider constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) - protected override fun init() { + override fun init() { super.init() // Default values are not ready here yet @@ -77,7 +77,7 @@ open class CombinedChart : BarLineChartBase, CombinedDataProvider // Old default behaviour isHighlightFullBarEnabled = true - mRenderer = CombinedChartRenderer(this, mAnimator, mViewPortHandler) + mRenderer = CombinedChartRenderer(this, mAnimator, viewPortHandler) } override val combinedData: CombinedData? @@ -87,7 +87,7 @@ open class CombinedChart : BarLineChartBase, CombinedDataProvider super.setData(data) setHighlighter(CombinedHighlighter(this, this)) (mRenderer as CombinedChartRenderer).createRenderers() - mRenderer.initBuffers() + mRenderer?.initBuffers() } /** @@ -100,22 +100,25 @@ open class CombinedChart : BarLineChartBase, CombinedDataProvider Log.e(LOG_TAG, "Can't select by touch. No data set.") return null } else { - val highlight = highlighter.getHighlight(x, y) - if (highlight == null || !isHighlightFullBarEnabled) { - return highlight + highlighter?.let { + val highlight = it.getHighlight(x, y) + if (highlight == null || !isHighlightFullBarEnabled) { + return highlight + } + + // For isHighlightFullBarEnabled, remove stackIndex + return Highlight( + highlight.x, + highlight.y, + highlight.xPx, + highlight.yPx, + highlight.dataSetIndex, + -1, + highlight.axis + ) } - - // For isHighlightFullBarEnabled, remove stackIndex - return Highlight( - highlight.x, - highlight.y, - highlight.xPx, - highlight.yPx, - highlight.dataSetIndex, - -1, - highlight.axis - ) } + return null } override val lineData: LineData? @@ -196,47 +199,49 @@ open class CombinedChart : BarLineChartBase, CombinedDataProvider override fun drawMarkers(canvas: Canvas) { // if there is no marker view or drawing marker is disabled - if (mMarkers == null || !isDrawMarkersEnabled || !valuesToHighlight()) { + if (!isDrawMarkersEnabled || !valuesToHighlight()) { return } - for (i in mIndicesToHighlight.indices) { - val highlight = mIndicesToHighlight[i] - val dataset = mData!!.getDataSetByHighlight(highlight) + highlighted?.let { + for (i in it.indices) { + val highlight = it[i] + val dataset = mData!!.getDataSetByHighlight(highlight) - val e = mData!!.getEntryForHighlight(highlight) - if (e == null || dataset == null) { - continue - } + val e = mData!!.getEntryForHighlight(highlight) + if (e == null || dataset == null) { + continue + } - @Suppress("UNCHECKED_CAST") - val set = dataset as IDataSet - val entryIndex = set.getEntryIndex(e) + @Suppress("UNCHECKED_CAST") + val set = dataset as IDataSet + val entryIndex = set.getEntryIndex(e) - // make sure entry not null - if (entryIndex > set.entryCount * mAnimator.phaseX) { - continue - } + // make sure entry not null + if (entryIndex > set.entryCount * mAnimator.phaseX) { + continue + } - val pos = getMarkerPosition(highlight) + val pos = getMarkerPosition(highlight) - // check bounds - if (!mViewPortHandler.isInBounds(pos[0], pos[1])) { - continue - } + // check bounds + if (!viewPortHandler.isInBounds(pos[0], pos[1])) { + continue + } - // callbacks to update the content - if (!mMarkers.isEmpty()) { - val markerItem = mMarkers[i % mMarkers.size] - markerItem.refreshContent(e, highlight) + // callbacks to update the content + if (!marker.isEmpty()) { + val markerItem = marker[i % marker.size] + markerItem.refreshContent(e, highlight) - // draw the marker - markerItem.draw(canvas, pos[0], pos[1]) + // draw the marker + markerItem.draw(canvas, pos[0], pos[1]) + } } } } - override fun getAccessibilityDescription(): String { - return "This is a combined chart" - } + override val accessibilityDescription: String + get() = "This is a combined chart" + } 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 c2927d7d0..a32375f81 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 @@ -36,19 +36,19 @@ open class HorizontalBarChart : BarChart { constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) override fun init() { - mViewPortHandler = HorizontalViewPortHandler() + viewPortHandler = HorizontalViewPortHandler() super.init() - mLeftAxisTransformer = TransformerHorizontalBarChart(mViewPortHandler) - mRightAxisTransformer = TransformerHorizontalBarChart(mViewPortHandler) + mLeftAxisTransformer = TransformerHorizontalBarChart(viewPortHandler) + mRightAxisTransformer = TransformerHorizontalBarChart(viewPortHandler) - mRenderer = HorizontalBarChartRenderer(this, mAnimator, mViewPortHandler) + mRenderer = HorizontalBarChartRenderer(this, mAnimator, viewPortHandler) setHighlighter(HorizontalBarHighlighter(this)) - mAxisRendererLeft = YAxisRendererHorizontalBarChart(mViewPortHandler, mAxisLeft, mLeftAxisTransformer) - mAxisRendererRight = YAxisRendererHorizontalBarChart(mViewPortHandler, mAxisRight, mRightAxisTransformer) - mXAxisRenderer = XAxisRendererHorizontalBarChart(mViewPortHandler, mXAxis, mLeftAxisTransformer) + mAxisRendererLeft = YAxisRendererHorizontalBarChart(viewPortHandler, mAxisLeft, mLeftAxisTransformer) + mAxisRendererRight = YAxisRendererHorizontalBarChart(viewPortHandler, mAxisRight, mRightAxisTransformer) + mXAxisRenderer = XAxisRendererHorizontalBarChart(viewPortHandler, mXAxis, mLeftAxisTransformer) } private val mOffsetsBuffer = RectF() @@ -59,65 +59,67 @@ open class HorizontalBarChart : BarChart { offsets.top = 0f offsets.bottom = 0f - if (mLegend == null || !mLegend.isEnabled || mLegend.isDrawInsideEnabled) { + if (legend == null || !legend!!.isEnabled || legend!!.isDrawInsideEnabled) { return } - when (mLegend.orientation) { - LegendOrientation.VERTICAL -> when (mLegend.horizontalAlignment) { - LegendHorizontalAlignment.LEFT -> offsets.left += min( - mLegend.mNeededWidth, - mViewPortHandler.chartWidth * mLegend.maxSizePercent - ) + mLegend.xOffset - - LegendHorizontalAlignment.RIGHT -> offsets.right += min( - mLegend.mNeededWidth, - mViewPortHandler.chartWidth * mLegend.maxSizePercent - ) + mLegend.xOffset - - LegendHorizontalAlignment.CENTER -> when (mLegend.verticalAlignment) { - LegendVerticalAlignment.TOP -> offsets.top += min( - mLegend.mNeededHeight, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + mLegend.yOffset - - LegendVerticalAlignment.BOTTOM -> offsets.bottom += min( - mLegend.mNeededHeight, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + mLegend.yOffset - - else -> {} - } - } - - LegendOrientation.HORIZONTAL -> when (mLegend.verticalAlignment) { - LegendVerticalAlignment.TOP -> { - offsets.top += min( - mLegend.mNeededHeight, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + mLegend.yOffset - - if (mAxisLeft.isEnabled && mAxisLeft.isDrawLabelsEnabled) { - offsets.top += mAxisLeft.getRequiredHeightSpace( - mAxisRendererLeft.paintAxisLabels - ) + legend?.let { legend -> + 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 -> {} } } - LegendVerticalAlignment.BOTTOM -> { - offsets.bottom += min( - mLegend.mNeededHeight, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + mLegend.yOffset + LegendOrientation.HORIZONTAL -> when (legend.verticalAlignment) { + LegendVerticalAlignment.TOP -> { + offsets.top += min( + legend.mNeededHeight, + viewPortHandler.chartHeight * legend.maxSizePercent + ) + legend.yOffset + + if (mAxisLeft.isEnabled && mAxisLeft.isDrawLabelsEnabled) { + offsets.top += mAxisLeft.getRequiredHeightSpace( + mAxisRendererLeft.paintAxisLabels + ) + } + } - if (mAxisRight.isEnabled && mAxisRight.isDrawLabelsEnabled) { - offsets.bottom += mAxisRight.getRequiredHeightSpace( - mAxisRendererRight.paintAxisLabels - ) + LegendVerticalAlignment.BOTTOM -> { + offsets.bottom += min( + legend.mNeededHeight, + viewPortHandler.chartHeight * legend.maxSizePercent + ) + legend.yOffset + + if (mAxisRight.isEnabled && mAxisRight.isDrawLabelsEnabled) { + offsets.bottom += mAxisRight.getRequiredHeightSpace( + mAxisRendererRight.paintAxisLabels + ) + } } - } - else -> {} + else -> {} + } } } } @@ -149,13 +151,21 @@ open class HorizontalBarChart : BarChart { if (mXAxis.isEnabled) { // offsets for x-labels - if (mXAxis.position == XAxisPosition.BOTTOM) { - offsetLeft += xLabelWidth - } else if (mXAxis.position == XAxisPosition.TOP) { - offsetRight += xLabelWidth - } else if (mXAxis.position == XAxisPosition.BOTH_SIDED) { - offsetLeft += xLabelWidth - offsetRight += xLabelWidth + when (mXAxis.position) { + XAxisPosition.BOTTOM -> { + offsetLeft += xLabelWidth + } + XAxisPosition.TOP -> { + offsetRight += xLabelWidth + } + XAxisPosition.BOTH_SIDED -> { + offsetLeft += xLabelWidth + offsetRight += xLabelWidth + } + + XAxisPosition.TOP_INSIDE -> TODO() + XAxisPosition.BOTTOM_INSIDE -> TODO() + null -> Log.w(LOG_TAG, "XAxisPosition is null") } } @@ -166,19 +176,19 @@ open class HorizontalBarChart : BarChart { val minOffset = mMinOffset.convertDpToPixel() - mViewPortHandler.restrainViewPort( + viewPortHandler.restrainViewPort( max(minOffset, offsetLeft), max(minOffset, offsetTop), max(minOffset, offsetRight), max(minOffset, offsetBottom) ) - if (mLogEnabled) { + if (isLogEnabled) { Log.i( LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom ) - Log.i(LOG_TAG, "Content: " + mViewPortHandler.contentRect) + Log.i(LOG_TAG, "Content: " + viewPortHandler.contentRect) } prepareOffsetMatrix() @@ -220,7 +230,7 @@ open class HorizontalBarChart : BarChart { } } - protected var mGetPositionBuffer: FloatArray = FloatArray(2) + protected var getPositionBuffer: FloatArray = FloatArray(2) /** * Returns a recyclable MPPointF instance. @@ -230,7 +240,7 @@ open class HorizontalBarChart : BarChart { return null } - val vals = mGetPositionBuffer + val vals = getPositionBuffer vals[0] = e.y vals[1] = e.x @@ -245,20 +255,20 @@ open class HorizontalBarChart : BarChart { */ override fun getHighlightByTouchPoint(x: Float, y: Float): Highlight? { if (mData == null) { - if (mLogEnabled) { + if (isLogEnabled) { Log.e(LOG_TAG, "Can't select by touch. No data set.") } return null } else { - return highlighter.getHighlight(y, x) // switch x and y + return highlighter?.getHighlight(y, x) // switch x and y } } override val lowestVisibleX: Float get() { getTransformer(AxisDependency.LEFT)!!.getValuesByTouchPoint( - mViewPortHandler.contentLeft(), - mViewPortHandler.contentBottom(), posForGetLowestVisibleX + viewPortHandler.contentLeft(), + viewPortHandler.contentBottom(), posForGetLowestVisibleX ) return max(mXAxis.mAxisMinimum.toDouble(), posForGetLowestVisibleX.y).toFloat() } @@ -266,8 +276,8 @@ open class HorizontalBarChart : BarChart { override val highestVisibleX: Float get() { getTransformer(AxisDependency.LEFT)!!.getValuesByTouchPoint( - mViewPortHandler.contentLeft(), - mViewPortHandler.contentTop(), posForGetHighestVisibleX + viewPortHandler.contentLeft(), + viewPortHandler.contentTop(), posForGetHighestVisibleX ) return min(mXAxis.mAxisMaximum.toDouble(), posForGetHighestVisibleX.y).toFloat() } @@ -277,33 +287,33 @@ open class HorizontalBarChart : BarChart { */ override fun setVisibleXRangeMaximum(maxXRange: Float) { val xScale = mXAxis.mAxisRange / (maxXRange) - mViewPortHandler.setMinimumScaleY(xScale) + viewPortHandler.setMinimumScaleY(xScale) } override fun setVisibleXRangeMinimum(minXRange: Float) { val xScale = mXAxis.mAxisRange / (minXRange) - mViewPortHandler.setMaximumScaleY(xScale) + viewPortHandler.setMaximumScaleY(xScale) } override fun setVisibleXRange(minXRange: Float, maxXRange: Float) { val minScale = mXAxis.mAxisRange / minXRange val maxScale = mXAxis.mAxisRange / maxXRange - mViewPortHandler.setMinMaxScaleY(minScale, maxScale) + viewPortHandler.setMinMaxScaleY(minScale, maxScale) } override fun setVisibleYRangeMaximum(maxYRange: Float, axis: AxisDependency?) { val yScale = getAxisRange(axis) / maxYRange - mViewPortHandler.setMinimumScaleX(yScale) + viewPortHandler.setMinimumScaleX(yScale) } override fun setVisibleYRangeMinimum(minYRange: Float, axis: AxisDependency?) { val yScale = getAxisRange(axis) / minYRange - mViewPortHandler.setMaximumScaleX(yScale) + viewPortHandler.setMaximumScaleX(yScale) } override fun setVisibleYRange(minYRange: Float, maxYRange: Float, axis: AxisDependency?) { val minScale = getAxisRange(axis) / minYRange val maxScale = getAxisRange(axis) / maxYRange - mViewPortHandler.setMinMaxScaleX(minScale, maxScale) + viewPortHandler.setMinMaxScaleX(minScale, maxScale) } } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/LineChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/LineChart.kt index d0e7a7e73..3a6af3e4e 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/LineChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/LineChart.kt @@ -2,7 +2,6 @@ package com.github.mikephil.charting.charts import android.content.Context import android.util.AttributeSet -import com.github.mikephil.charting.data.ChartData import com.github.mikephil.charting.data.LineData import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider import com.github.mikephil.charting.renderer.LineChartRenderer @@ -16,7 +15,7 @@ open class LineChart : BarLineChartBase, LineDataProvider { override fun init() { super.init() - mRenderer = LineChartRenderer(this, mAnimator, mViewPortHandler) + mRenderer = LineChartRenderer(this, mAnimator, viewPortHandler) } override var lineData: LineData @@ -38,29 +37,27 @@ open class LineChart : BarLineChartBase, LineDataProvider { super.onDetachedFromWindow() } - override fun getAccessibilityDescription(): String { - val lineData = lineData - val numberOfPoints = lineData.entryCount - - // Min and max values... - val yAxisValueFormatter = axisLeft.valueFormatter - val minVal = yAxisValueFormatter?.getFormattedValue(lineData.yMin, null) - val maxVal = yAxisValueFormatter?.getFormattedValue(lineData.yMax, null) - - // Data range... - val xAxisValueFormatter = xAxis.valueFormatter - val minRange = xAxisValueFormatter?.getFormattedValue(lineData.xMin, null) - val maxRange = xAxisValueFormatter?.getFormattedValue(lineData.xMax, null) - val entries = if (numberOfPoints == 1) "entry" else "entries" - return String.format( - Locale.getDefault(), "The line chart has %d %s. " + - "The minimum value is %s and maximum value is %s." + - "Data ranges from %s to %s.", - numberOfPoints, entries, minVal, maxVal, minRange, maxRange - ) - } + override val accessibilityDescription: String + get() { + val lineData = lineData + val numberOfPoints = lineData.entryCount + + // Min and max values... + val yAxisValueFormatter = axisLeft.valueFormatter + val minVal = yAxisValueFormatter?.getFormattedValue(lineData.yMin, null) + val maxVal = yAxisValueFormatter?.getFormattedValue(lineData.yMax, null) + + // Data range... + val xAxisValueFormatter = xAxis.valueFormatter + val minRange = xAxisValueFormatter?.getFormattedValue(lineData.xMin, null) + val maxRange = xAxisValueFormatter?.getFormattedValue(lineData.xMax, null) + val entries = if (numberOfPoints == 1) "entry" else "entries" + return String.format( + Locale.getDefault(), "The line chart has %d %s. " + + "The minimum value is %s and maximum value is %s." + + "Data ranges from %s to %s.", + numberOfPoints, entries, minVal, maxVal, minRange, maxRange + ) + } - override fun setData(data: LineData?) { - super.setData(data) - } } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/PieChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/PieChart.kt index b87374e7b..bc4015f51 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/PieChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/PieChart.kt @@ -7,7 +7,6 @@ import android.graphics.Typeface import android.text.TextUtils import android.util.AttributeSet import com.github.mikephil.charting.components.XAxis -import com.github.mikephil.charting.data.ChartData import com.github.mikephil.charting.data.PieData import com.github.mikephil.charting.highlight.Highlight import com.github.mikephil.charting.highlight.PieHighlighter @@ -144,26 +143,25 @@ class PieChart : PieRadarChartBase { override fun init() { super.init() - mRenderer = PieChartRenderer(this, mAnimator, mViewPortHandler) - mXAxis = null - - mHighlighter = PieHighlighter(this) + mRenderer = PieChartRenderer(this, mAnimator, viewPortHandler) + highlighter = PieHighlighter(this) } - protected override fun onDraw(canvas: Canvas) { + override fun onDraw(canvas: Canvas) { super.onDraw(canvas) if (mData == null) return - mRenderer.drawData(canvas) + mRenderer?.drawData(canvas) - if (valuesToHighlight()) mRenderer.drawHighlighted(canvas, mIndicesToHighlight) + if (valuesToHighlight()) + mRenderer?.drawHighlighted(canvas, highlighted!!) - mRenderer.drawExtras(canvas) + mRenderer?.drawExtras(canvas) - mRenderer.drawValues(canvas) + mRenderer?.drawValues(canvas) - mLegendRenderer.renderLegend(canvas) + legendRenderer?.renderLegend(canvas) drawDescription(canvas) @@ -196,7 +194,7 @@ class PieChart : PieRadarChartBase { calcAngles() } - override fun getMarkerPosition(highlight: Highlight): FloatArray { + override fun getMarkerPosition(high: Highlight): FloatArray { val center = this.centerCircleBox var r = radius @@ -210,7 +208,7 @@ class PieChart : PieRadarChartBase { val rotationAngle = rotationAngle - val entryIndex = highlight.x.toInt() + val entryIndex = high.x.toInt() // offset needed to center the drawn text in the slice val offset = this.drawAngles[entryIndex] / 2 @@ -321,10 +319,11 @@ class PieChart : PieRadarChartBase { if (!valuesToHighlight()) return false // check if the xvalue for the given dataset needs highlight - for (highlight in mIndicesToHighlight) - if (highlight.x.toInt() == index) - return true - + highlighted?.let { + for (highlight in it) + if (highlight.x.toInt() == index) + return true + } return false } @@ -339,9 +338,8 @@ class PieChart : PieRadarChartBase { * This will throw an exception, PieChart has no XAxis object. */ @Deprecated("") - override fun getXAxis(): XAxis { - throw RuntimeException("PieChart has no XAxis") - } + override val xAxis: XAxis + get() = throw RuntimeException("PieChart has no XAxis") override fun getIndexForAngle(angle: Float): Int { // take the current angle of the chart into consideration @@ -404,7 +402,12 @@ class PieChart : PieRadarChartBase { } override val requiredLegendOffset: Float - get() = mLegendRenderer.labelPaint.textSize * 2f + get() { + legendRenderer?.let { + return it.labelPaint.textSize * 2f + } + return 0f + } override val requiredBaseOffset: Float get() = 0f @@ -578,7 +581,7 @@ class PieChart : PieRadarChartBase { this.mMinAngleForSlices = minAngle } - protected override fun onDetachedFromWindow() { + override fun onDetachedFromWindow() { // releases the bitmap in the renderer to avoid oom error if (mRenderer != null && mRenderer is PieChartRenderer) { (mRenderer as PieChartRenderer).releaseBitmap() @@ -586,32 +589,30 @@ class PieChart : PieRadarChartBase { super.onDetachedFromWindow() } - override fun getAccessibilityDescription(): String { - val pieData = getData() as PieData? + override val accessibilityDescription: String + get() { + val pieData = getData() - var entryCount = 0 - if (pieData != null) entryCount = pieData.entryCount + var entryCount = 0 + if (pieData != null) entryCount = pieData.entryCount - val builder = StringBuilder() + val builder = StringBuilder() - builder.append(String.format(Locale.getDefault(), "The pie chart has %d entries.", entryCount)) + builder.append(String.format(Locale.getDefault(), "The pie chart has %d entries.", entryCount)) - for (i in 0..>> override fun onTouchEvent(event: MotionEvent?): Boolean { // use the Pie- and RadarChart listener own listener - return if (mTouchEnabled && mChartTouchListener != null) mChartTouchListener.onTouch(this, event) + return if (mTouchEnabled && mChartTouchListener != null) + mChartTouchListener!!.onTouch(this, event) else super.onTouchEvent(event) } @@ -107,7 +108,7 @@ abstract class PieRadarChartBase>> calcMinMax() - if (mLegend != null) mLegendRenderer.computeLegend(mData!!) + if (legend != null) legendRenderer?.computeLegend(mData!!) calculateOffsets() } @@ -118,113 +119,145 @@ abstract class PieRadarChartBase>> var legendBottom = 0f var legendTop = 0f - if (mLegend != null && mLegend.isEnabled && !mLegend.isDrawInsideEnabled) { - val fullLegendWidth = min( - mLegend.mNeededWidth, - mViewPortHandler.chartWidth * mLegend.maxSizePercent - ) - - when (mLegend.orientation) { - LegendOrientation.VERTICAL -> { - var xLegendOffset = 0f - - if (mLegend.horizontalAlignment == LegendHorizontalAlignment.LEFT - || mLegend.horizontalAlignment == LegendHorizontalAlignment.RIGHT - ) { - if (mLegend.verticalAlignment == LegendVerticalAlignment.CENTER) { - // this is the space between the legend and the chart - val spacing = 13f.convertDpToPixel() - - xLegendOffset = fullLegendWidth + spacing - } else { - // this is the space between the legend and the chart - val spacing = 8f.convertDpToPixel() - - val legendWidth = fullLegendWidth + spacing - val legendHeight = mLegend.mNeededHeight + mLegend.mTextHeightMax - - val center = getCenter() - - val bottomX = if (mLegend.horizontalAlignment == - LegendHorizontalAlignment.RIGHT - ) - width - legendWidth + 15f - else - legendWidth - 15f - val bottomY = legendHeight + 15f - val distLegend = distanceToCenter(bottomX, bottomY) - - val reference = getPosition( - center, this.radius, - getAngleForPoint(bottomX, bottomY) - ) - - val distReference = distanceToCenter(reference.x, reference.y) - val minOffset = 5f.convertDpToPixel() - - if (bottomY >= center.y && height - legendWidth > width) { - xLegendOffset = legendWidth - } else if (distLegend < distReference) { - val diff = distReference - distLegend - xLegendOffset = minOffset + diff + legend?.let { legend -> + if (legend.isEnabled && !legend.isDrawInsideEnabled) { + val fullLegendWidth = min( + legend.mNeededWidth, + viewPortHandler.chartWidth * legend.maxSizePercent + ) + val fullLegendHeight = min( + legend.mNeededHeight, + viewPortHandler.chartHeight * legend.maxSizePercent + ) + + when (legend.orientation) { + LegendOrientation.VERTICAL -> { + when (legend.horizontalAlignment) { + LegendHorizontalAlignment.LEFT -> legendLeft = fullLegendWidth + LegendHorizontalAlignment.RIGHT -> legendRight = fullLegendWidth + LegendHorizontalAlignment.CENTER -> { + // do nothing for center } - - recycleInstance(center) - recycleInstance(reference) } } - when (mLegend.horizontalAlignment) { - LegendHorizontalAlignment.LEFT -> legendLeft = xLegendOffset - LegendHorizontalAlignment.RIGHT -> legendRight = xLegendOffset - LegendHorizontalAlignment.CENTER -> when (mLegend.verticalAlignment) { - LegendVerticalAlignment.TOP -> legendTop = min( - mLegend.mNeededHeight, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + LegendOrientation.HORIZONTAL -> { + when (legend.verticalAlignment) { + LegendVerticalAlignment.TOP -> legendTop = fullLegendHeight + LegendVerticalAlignment.BOTTOM -> legendBottom = fullLegendHeight + LegendVerticalAlignment.CENTER -> { + // do nothing for center + } + } + } + } + } - LegendVerticalAlignment.BOTTOM -> legendBottom = min( - mLegend.mNeededHeight, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + if (legend.isEnabled && !legend.isDrawInsideEnabled) { + val fullLegendWidth = min( + legend.mNeededWidth, + viewPortHandler.chartWidth * legend.maxSizePercent + ) + + when (legend.orientation) { + LegendOrientation.VERTICAL -> { + var xLegendOffset = 0f + + if (legend.horizontalAlignment == LegendHorizontalAlignment.LEFT + || legend.horizontalAlignment == LegendHorizontalAlignment.RIGHT + ) { + if (legend.verticalAlignment == LegendVerticalAlignment.CENTER) { + // this is the space between the legend and the chart + val spacing = 13f.convertDpToPixel() + + xLegendOffset = fullLegendWidth + spacing + } else { + // this is the space between the legend and the chart + val spacing = 8f.convertDpToPixel() + + val legendWidth = fullLegendWidth + spacing + val legendHeight = legend.mNeededHeight + legend.mTextHeightMax + + val bottomX = if (legend.horizontalAlignment == + LegendHorizontalAlignment.RIGHT + ) + width - legendWidth + 15f + else + legendWidth - 15f + val bottomY = legendHeight + 15f + val distLegend = distanceToCenter(bottomX, bottomY) + + val reference = getPosition( + center, this.radius, + getAngleForPoint(bottomX, bottomY) + ) + + val distReference = distanceToCenter(reference.x, reference.y) + val minOffset = 5f.convertDpToPixel() + + if (bottomY >= center.y && height - legendWidth > width) { + xLegendOffset = legendWidth + } else if (distLegend < distReference) { + val diff = distReference - distLegend + xLegendOffset = minOffset + diff + } + + recycleInstance(center) + recycleInstance(reference) + } + } - LegendVerticalAlignment.CENTER -> Log.e(LOG_TAG, "LegendCenter/VerticalCenter not supported for PieRadarChart") + when (legend.horizontalAlignment) { + LegendHorizontalAlignment.LEFT -> legendLeft = xLegendOffset + LegendHorizontalAlignment.RIGHT -> legendRight = xLegendOffset + LegendHorizontalAlignment.CENTER -> when (legend.verticalAlignment) { + LegendVerticalAlignment.TOP -> legendTop = min( + legend.mNeededHeight, + viewPortHandler.chartHeight * legend.maxSizePercent + ) + + LegendVerticalAlignment.BOTTOM -> legendBottom = min( + legend.mNeededHeight, + viewPortHandler.chartHeight * legend.maxSizePercent + ) + + LegendVerticalAlignment.CENTER -> Log.e(LOG_TAG, "LegendCenter/VerticalCenter not supported for PieRadarChart") + } } } - } - LegendOrientation.HORIZONTAL -> { - val yLegendOffset: Float + LegendOrientation.HORIZONTAL -> { + val yLegendOffset: Float - if (mLegend.verticalAlignment == LegendVerticalAlignment.TOP || - mLegend.verticalAlignment == LegendVerticalAlignment.BOTTOM - ) { - // It's possible that we do not need this offset anymore as it - // is available through the extraOffsets, but changing it can mean - // changing default visibility for existing apps. + if (legend.verticalAlignment == LegendVerticalAlignment.TOP || + legend.verticalAlignment == LegendVerticalAlignment.BOTTOM + ) { + // It's possible that we do not need this offset anymore as it + // is available through the extraOffsets, but changing it can mean + // changing default visibility for existing apps. - val yOffset = this.requiredLegendOffset + val yOffset = this.requiredLegendOffset - yLegendOffset = min( - mLegend.mNeededHeight + yOffset, - mViewPortHandler.chartHeight * mLegend.maxSizePercent - ) + yLegendOffset = min( + legend.mNeededHeight + yOffset, + viewPortHandler.chartHeight * legend.maxSizePercent + ) - when (mLegend.verticalAlignment) { - LegendVerticalAlignment.TOP -> legendTop = yLegendOffset - LegendVerticalAlignment.BOTTOM -> legendBottom = yLegendOffset - LegendVerticalAlignment.CENTER -> Log.e(LOG_TAG, "LegendCenter/HorizontalCenter not supported for PieRadarChart") + when (legend.verticalAlignment) { + LegendVerticalAlignment.TOP -> legendTop = yLegendOffset + LegendVerticalAlignment.BOTTOM -> legendBottom = yLegendOffset + LegendVerticalAlignment.CENTER -> Log.e(LOG_TAG, "LegendCenter/HorizontalCenter not supported for PieRadarChart") + } } } } - } - legendLeft += this.requiredBaseOffset - legendRight += this.requiredBaseOffset - legendTop += this.requiredBaseOffset - legendBottom += this.requiredBaseOffset + legendLeft += this.requiredBaseOffset + legendRight += this.requiredBaseOffset + legendTop += this.requiredBaseOffset + legendBottom += this.requiredBaseOffset + } } - var minOffset = minOffset.convertDpToPixel() if (this is RadarChart) { @@ -245,12 +278,10 @@ abstract class PieRadarChartBase>> val offsetRight = max(minOffset, legendRight) val offsetBottom = max(minOffset, max(this.requiredBaseOffset, legendBottom)) - mViewPortHandler.restrainViewPort(offsetLeft, offsetTop, offsetRight, offsetBottom) + viewPortHandler.restrainViewPort(offsetLeft, offsetTop, offsetRight, offsetBottom) - if (mLogEnabled) Log.i( - LOG_TAG, ("offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop - + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom) - ) + if (isLogEnabled) + Log.i(LOG_TAG, "offsetLeft: $offsetLeft, offsetTop: $offsetTop, offsetRight: $offsetRight, offsetBottom: $offsetBottom") } /** @@ -259,7 +290,7 @@ abstract class PieRadarChartBase>> * 90° is EAST, ... */ fun getAngleForPoint(x: Float, y: Float): Float { - centerOffsets?.let { c -> + centerOffsets.let { c -> val tx = (x - c.x).toDouble() val ty = (y - c.y).toDouble() @@ -280,7 +311,6 @@ abstract class PieRadarChartBase>> recycleInstance(c) return angle } - return 0f } /** @@ -304,7 +334,7 @@ abstract class PieRadarChartBase>> * Returns the distance of a certain point on the chart to the center of the chart. */ fun distanceToCenter(x: Float, y: Float): Float { - centerOffsets?.let { c -> + centerOffsets.let { c -> val dist: Float @@ -327,7 +357,6 @@ abstract class PieRadarChartBase>> return dist } - return 0f } /** @@ -356,7 +385,7 @@ abstract class PieRadarChartBase>> * returns the diameter of the pie- or radar-chart */ get() { - val content = mViewPortHandler.contentRect + val content = viewPortHandler.contentRect content.left += extraLeftOffset content.top += extraTopOffset content.right -= extraRightOffset diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/RadarChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/RadarChart.kt index 22ec0caea..c74049f38 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/RadarChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/RadarChart.kt @@ -6,7 +6,6 @@ import android.graphics.Color import android.util.AttributeSet import com.github.mikephil.charting.components.YAxis import com.github.mikephil.charting.components.YAxis.AxisDependency -import com.github.mikephil.charting.data.ChartData import com.github.mikephil.charting.data.RadarData import com.github.mikephil.charting.highlight.RadarHighlighter import com.github.mikephil.charting.renderer.RadarChartRenderer @@ -102,11 +101,11 @@ class RadarChart : PieRadarChartBase { mWebLineWidth = 1.5f.convertDpToPixel() mInnerWebLineWidth = 0.75f.convertDpToPixel() - mRenderer = RadarChartRenderer(this, mAnimator, mViewPortHandler) - mYAxisRenderer = YAxisRendererRadarChart(mViewPortHandler, mYAxis!!, this) - mXAxisRenderer = XAxisRendererRadarChart(mViewPortHandler, mXAxis, this) + mRenderer = RadarChartRenderer(this, mAnimator, viewPortHandler) + mYAxisRenderer = YAxisRendererRadarChart(viewPortHandler, mYAxis!!, this) + mXAxisRenderer = XAxisRendererRadarChart(viewPortHandler, mXAxis, this) - mHighlighter = RadarHighlighter(this) + highlighter = RadarHighlighter(this) } override fun calcMinMax() { @@ -124,13 +123,14 @@ class RadarChart : PieRadarChartBase { mYAxisRenderer!!.computeAxis(mYAxis!!.mAxisMinimum, mYAxis!!.mAxisMaximum, mYAxis!!.isInverted) mXAxisRenderer!!.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false) - if (mLegend != null && !mLegend.isLegendCustom) mLegendRenderer.computeLegend(data) + if (legend != null && !legend!!.isLegendCustom) + legendRenderer?.computeLegend(data) calculateOffsets() } } - protected override fun onDraw(canvas: Canvas) { + override fun onDraw(canvas: Canvas) { super.onDraw(canvas) if (mData == null) return @@ -141,21 +141,23 @@ class RadarChart : PieRadarChartBase { mXAxisRenderer!!.renderAxisLabels(canvas) - if (mDrawWeb) mRenderer.drawExtras(canvas) + if (mDrawWeb) + mRenderer?.drawExtras(canvas) if (mYAxis!!.isEnabled && mYAxis!!.isDrawLimitLinesBehindDataEnabled) mYAxisRenderer!!.renderLimitLines(canvas) - mRenderer.drawData(canvas) + mRenderer?.drawData(canvas) - if (valuesToHighlight()) mRenderer.drawHighlighted(canvas, mIndicesToHighlight) + if (valuesToHighlight()) + mRenderer?.drawHighlighted(canvas, highlighted!!) if (mYAxis!!.isEnabled && !mYAxis!!.isDrawLimitLinesBehindDataEnabled) mYAxisRenderer!!.renderLimitLines(canvas) mYAxisRenderer!!.renderAxisLabels(canvas) - mRenderer.drawValues(canvas) + mRenderer?.drawValues(canvas) - mLegendRenderer.renderLegend(canvas) + legendRenderer?.renderLegend(canvas) drawDescription(canvas) @@ -168,7 +170,7 @@ class RadarChart : PieRadarChartBase { * */ get() { - val content = mViewPortHandler.contentRect + val content = viewPortHandler.contentRect return min(content.width() / 2f, content.height() / 2f) / mYAxis!!.mAxisRange } @@ -270,14 +272,19 @@ class RadarChart : PieRadarChartBase { } override val requiredLegendOffset: Float - get() = mLegendRenderer.labelPaint.textSize * 4f + get() { + legendRenderer?.let { + return it.labelPaint.textSize * 4f + } + return 0f + } override val requiredBaseOffset: Float get() = if (mXAxis.isEnabled && mXAxis.isDrawLabelsEnabled) mXAxis.mLabelWidth.toFloat() else 10f.convertDpToPixel() override val radius: Float get() { - val content = mViewPortHandler.contentRect + val content = viewPortHandler.contentRect return min(content.width() / 2f, content.height() / 2f) } @@ -287,10 +294,8 @@ class RadarChart : PieRadarChartBase { override val yChartMax: Float get() = mYAxis!!.mAxisMaximum - override fun setData(data: RadarData?) { - super.setData(data) - } - + override val accessibilityDescription: String + get() = "This is a Radar chart" /** * Returns the minimum value this chart can display on it's y-axis. @@ -303,8 +308,4 @@ class RadarChart : PieRadarChartBase { */ val yRange: Float get() = mYAxis!!.mAxisRange - - override fun getAccessibilityDescription(): String { - return "This is a Radar chart" - } } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/ScatterChart.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/ScatterChart.kt index eb7703821..8cdd0aee5 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/ScatterChart.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/ScatterChart.kt @@ -2,7 +2,6 @@ package com.github.mikephil.charting.charts import android.content.Context import android.util.AttributeSet -import com.github.mikephil.charting.data.ChartData import com.github.mikephil.charting.data.ScatterData import com.github.mikephil.charting.interfaces.dataprovider.ScatterDataProvider import com.github.mikephil.charting.renderer.ScatterChartRenderer @@ -20,10 +19,10 @@ class ScatterChart : BarLineChartBase, ScatterDataProvider { constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) - protected override fun init() { + override fun init() { super.init() - mRenderer = ScatterChartRenderer(this, mAnimator, mViewPortHandler) + mRenderer = ScatterChartRenderer(this, mAnimator, viewPortHandler) xAxis.spaceMin = 0.5f xAxis.spaceMax = 0.5f @@ -63,11 +62,6 @@ class ScatterChart : BarLineChartBase, ScatterDataProvider { } } - override fun getAccessibilityDescription(): String { - return "This is scatter chart" - } - - override fun setData(data: ScatterData?) { - super.setData(data) - } + override val accessibilityDescription: String + get() = "This is scatter chart" } diff --git a/app/src/main/kotlin/info/appdev/chartexample/AnotherBarActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/AnotherBarActivity.kt index 18c1735be..c7c137d19 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/AnotherBarActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/AnotherBarActivity.kt @@ -31,7 +31,7 @@ class AnotherBarActivity : DemoBase(), OnSeekBarChangeListener { binding.seekBarX.setOnSeekBarChangeListener(this) binding.seekBarY.setOnSeekBarChangeListener(this) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be drawn binding.chart1.setMaxVisibleValueCount(60) @@ -55,7 +55,7 @@ class AnotherBarActivity : DemoBase(), OnSeekBarChangeListener { // add a nice and smooth animation binding.chart1.animateY(1500) - binding.chart1.legend.isEnabled = false + binding.chart1.legend?.isEnabled = false } override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivity.kt index 4e98de39c..6c039bd79 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivity.kt @@ -53,7 +53,7 @@ class BarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSelect binding.chart1.setDrawBarShadow(false) binding.chart1.setDrawValueAboveBar(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be // drawn @@ -93,15 +93,16 @@ class BarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSelect rightAxis.spaceTop = 15f rightAxis.axisMinimum = 0f// this replaces setStartAtZero(true) - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.form = LegendForm.SQUARE - l.formSize = 9f - l.textSize = 11f - l.xEntrySpace = 4f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + form = LegendForm.SQUARE + formSize = 9f + textSize = 11f + xEntrySpace = 4f + } val mv = XYMarkerView(this, xAxisFormatter) mv.chartView = binding.chart1 // For bounds control diff --git a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt index 0e356c82e..33e119f2a 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt @@ -45,7 +45,7 @@ class BarChartActivityMultiDataset : DemoBase(), OnSeekBarChangeListener, OnChar binding.seekBarY.setOnSeekBarChangeListener(this) binding.chart1.setOnChartValueSelectedListener(this) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // chart.setDrawBorders(true); @@ -65,16 +65,17 @@ class BarChartActivityMultiDataset : DemoBase(), OnSeekBarChangeListener, OnChar binding.seekBarX.progress = 10 binding.seekBarY.progress = 100 - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(true) - l.typeface = tfLight - l.yOffset = 0f - l.xOffset = 10f - l.yEntrySpace = 0f - l.textSize = 8f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(true) + typeface = tfLight + yOffset = 0f + xOffset = 10f + yEntrySpace = 0f + textSize = 8f + } val xAxis = binding.chart1.xAxis xAxis.typeface = tfLight diff --git a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivitySinus.kt b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivitySinus.kt index 902f2f71e..1e409a6d7 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivitySinus.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivitySinus.kt @@ -35,7 +35,7 @@ class BarChartActivitySinus : DemoBase(), OnSeekBarChangeListener { binding.chart1.setDrawBarShadow(false) binding.chart1.setDrawValueAboveBar(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be drawn binding.chart1.setMaxVisibleValueCount(60) @@ -72,7 +72,7 @@ class BarChartActivitySinus : DemoBase(), OnSeekBarChangeListener { binding.seekbarValues.setOnSeekBarChangeListener(this) binding.seekbarValues.progress = 150 // set data - binding.chart1.legend.apply { + binding.chart1.legend?.apply { verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT orientation = Legend.LegendOrientation.HORIZONTAL diff --git a/app/src/main/kotlin/info/appdev/chartexample/BarChartPositiveNegative.kt b/app/src/main/kotlin/info/appdev/chartexample/BarChartPositiveNegative.kt index d0ab71adf..4daa3996a 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BarChartPositiveNegative.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BarChartPositiveNegative.kt @@ -39,7 +39,7 @@ class BarChartPositiveNegative : DemoBase() { binding.chart1.setDrawBarShadow(false) binding.chart1.setDrawValueAboveBar(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // scaling can now only be done on x- and y-axis separately binding.chart1.setPinchZoom(false) @@ -67,7 +67,7 @@ class BarChartPositiveNegative : DemoBase() { left.zeroLineColor = Color.GRAY left.zeroLineWidth = 0.7f binding.chart1.axisRight.isEnabled = false - binding.chart1.legend.isEnabled = false + binding.chart1.legend?.isEnabled = false // THIS IS THE ORIGINAL DATA YOU WANT TO PLOT val data: MutableList = ArrayList() diff --git a/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt index 9e71b84fa..1333332d1 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BubbleChartActivity.kt @@ -39,7 +39,7 @@ class BubbleChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSel binding.seekBarX.setOnSeekBarChangeListener(this) binding.seekBarY.setOnSeekBarChangeListener(this) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setOnChartValueSelectedListener(this) binding.chart1.setDrawGridBackground(false) binding.chart1.setTouchEnabled(true) @@ -54,12 +54,13 @@ class BubbleChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSel binding.seekBarX.progress = 10 binding.seekBarY.progress = 50 - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(false) - l.typeface = tfLight + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(false) + typeface = tfLight + } val yl = binding.chart1.axisLeft yl.typeface = tfLight diff --git a/app/src/main/kotlin/info/appdev/chartexample/CandleStickChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/CandleStickChartActivity.kt index 117e81923..aa876025a 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/CandleStickChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/CandleStickChartActivity.kt @@ -34,7 +34,7 @@ class CandleStickChartActivity : DemoBase(), OnSeekBarChangeListener { binding.seekBarX.setOnSeekBarChangeListener(this) binding.seekBarY.setOnSeekBarChangeListener(this) binding.chart1.setBackgroundColor(Color.WHITE) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be drawn binding.chart1.setMaxVisibleValueCount(60) @@ -63,7 +63,7 @@ class CandleStickChartActivity : DemoBase(), OnSeekBarChangeListener { binding.seekBarX.progress = 40 binding.seekBarY.progress = 100 - binding.chart1.legend.isEnabled = false + binding.chart1.legend?.isEnabled = false } override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/CombinedChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/CombinedChartActivity.kt index a37f0ea07..fc26fa008 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/CombinedChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/CombinedChartActivity.kt @@ -44,7 +44,7 @@ class CombinedChartActivity : DemoBase() { binding = ActivityCombinedBinding.inflate(layoutInflater) setContentView(binding.root) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setBackgroundColor(Color.WHITE) binding.chart1.setDrawGridBackground(false) binding.chart1.setDrawBarShadow(false) @@ -55,12 +55,13 @@ class CombinedChartActivity : DemoBase() { DrawOrder.BAR, DrawOrder.BUBBLE, DrawOrder.CANDLE, DrawOrder.LINE, DrawOrder.SCATTER ) - val l = binding.chart1.legend - l.isWordWrapEnabled = true - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) + binding.chart1.legend?.apply { + isWordWrapEnabled = true + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + } val rightAxis = binding.chart1.axisRight rightAxis.setDrawGridLines(false) diff --git a/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt index f6948fe13..293e754b9 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/CubicLineChartActivity.kt @@ -36,7 +36,7 @@ class CubicLineChartActivity : DemoBase(), OnSeekBarChangeListener { binding.chart1.setBackgroundColor(Color.rgb(104, 241, 175)) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) @@ -74,7 +74,7 @@ class CubicLineChartActivity : DemoBase(), OnSeekBarChangeListener { binding.seekBarX.progress = 45 binding.seekBarY.progress = 100 - binding.chart1.legend.isEnabled = false + binding.chart1.legend?.isEnabled = false binding.chart1.animateXY(2000, 2000) diff --git a/app/src/main/kotlin/info/appdev/chartexample/DrawChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/DrawChartActivity.kt index 93fa7310b..2ae50d85a 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/DrawChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/DrawChartActivity.kt @@ -49,7 +49,7 @@ class DrawChartActivity : DemoBase(), OnChartValueSelectedListener, OnDrawListen val yl = binding.chart1.axisLeft yl.typeface = tfRegular - binding.chart1.legend.isEnabled = false + binding.chart1.legend?.isEnabled = false // chart.setYRange(-40f, 40f, true); // call this to reset the changed y-range @@ -134,7 +134,7 @@ class DrawChartActivity : DemoBase(), OnChartValueSelectedListener, OnDrawListen Timber.i("DataSet drawn. ${dataSet.toSimpleString()}") // prepare the legend again - binding.chart1.getData()?.let { binding.chart1.legendRenderer.computeLegend(it) } + binding.chart1.getData()?.let { binding.chart1.legendRenderer?.computeLegend(it) } } override fun onEntryMoved(entry: Entry) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/DynamicalAddingActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/DynamicalAddingActivity.kt index 69c6a0693..9c3aeb84d 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/DynamicalAddingActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/DynamicalAddingActivity.kt @@ -33,7 +33,7 @@ class DynamicalAddingActivity : DemoBase(), OnChartValueSelectedListener { binding.chart1.setOnChartValueSelectedListener(this) binding.chart1.setDrawGridBackground(false) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setNoDataText("No chart data available. Use the menu to add entries and data sets!") // chart.getXAxis().setDrawLabels(false); diff --git a/app/src/main/kotlin/info/appdev/chartexample/FilledLineActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/FilledLineActivity.kt index 13ff978ab..638149c84 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/FilledLineActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/FilledLineActivity.kt @@ -41,13 +41,14 @@ class FilledLineActivity : DemoBase() { binding.chart1.setDrawBorders(true) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if disabled, scaling can be done on x- and y-axis separately binding.chart1.setPinchZoom(false) - val l = binding.chart1.legend - l.isEnabled = false + binding.chart1.legend?.apply { + isEnabled = false + } val xAxis = binding.chart1.xAxis xAxis.isEnabled = false diff --git a/app/src/main/kotlin/info/appdev/chartexample/HalfPieChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/HalfPieChartActivity.kt index 102d50997..87cba91d0 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/HalfPieChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/HalfPieChartActivity.kt @@ -38,7 +38,7 @@ class HalfPieChartActivity : DemoBase() { moveOffScreen() binding.chart1.setUsePercentValues(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setCenterTextTypeface(tfLight) binding.chart1.centerText = generateCenterSpannableText() @@ -65,14 +65,15 @@ class HalfPieChartActivity : DemoBase() { binding.chart1.animateY(1400, Easing.easeInOutQuad) - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.xEntrySpace = 7f - l.yEntrySpace = 0f - l.yOffset = 0f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + xEntrySpace = 7f + yEntrySpace = 0f + yOffset = 0f + } // entry label styling binding.chart1.setEntryLabelColor(Color.WHITE) diff --git a/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarChartActivity.kt index 24af475b0..e78eeb411 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarChartActivity.kt @@ -46,7 +46,7 @@ class HorizontalBarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartV binding.chart1.setDrawValueAboveBar(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be // drawn @@ -87,13 +87,14 @@ class HorizontalBarChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartV binding.seekBarY.progress = 50 binding.seekBarX.progress = 12 - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.formSize = 8f - l.xEntrySpace = 4f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + formSize = 8f + xEntrySpace = 4f + } } private fun setData(count: Int, range: Float) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarNegativeChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarNegativeChartActivity.kt index 5adc18e5c..e49a6b419 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarNegativeChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/HorizontalBarNegativeChartActivity.kt @@ -45,7 +45,7 @@ class HorizontalBarNegativeChartActivity : DemoBase(), OnSeekBarChangeListener, binding.chart1.setDrawBarShadow(false) binding.chart1.setDrawValueAboveBar(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be // drawn @@ -84,13 +84,14 @@ class HorizontalBarNegativeChartActivity : DemoBase(), OnSeekBarChangeListener, binding.seekBarY.progress = 50 binding.seekBarX.progress = 12 - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.formSize = 8f - l.xEntrySpace = 4f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + formSize = 8f + xEntrySpace = 4f + } } private fun setData(count: Int, range: Float) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt index ae9506413..f7045957a 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/InvertedLineChartActivity.kt @@ -40,7 +40,7 @@ class InvertedLineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartVa binding.chart1.setDrawGridBackground(false) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) @@ -83,10 +83,9 @@ class InvertedLineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartVa // chart.centerViewPort(10, 50); // get the legend (only possible after setting data) - val l = binding.chart1.legend - - // modify the legend ... - l.form = LegendForm.LINE + binding.chart1.legend?.apply { + form = LegendForm.LINE + } // don't forget to refresh the drawing binding.chart1.invalidate() diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartActivity.kt index 9e03f2cd4..6e3c4ff40 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartActivity.kt @@ -46,7 +46,7 @@ class LineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSelec binding.chart1.setBackgroundColor(Color.WHITE) // disable description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) @@ -137,7 +137,7 @@ class LineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSelec // get the legend (only possible after setting data) val legend = binding.chart1.legend - legend.form = LegendForm.LINE + legend?.form = LegendForm.LINE } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt index 213894e57..65296b71e 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartActivityColored.kt @@ -48,7 +48,7 @@ class LineChartActivityColored : DemoBase() { (data.getDataSetByIndex(0) as LineDataSet).circleHoleColor = color // no description text - chart.description.isEnabled = false + chart.description?.isEnabled = false // chart.setDrawHorizontalGrid(false); // @@ -76,8 +76,9 @@ class LineChartActivityColored : DemoBase() { chart.setData(data) // get the legend (only possible after setting data) - val l = chart.legend - l.isEnabled = false + chart.legend?.apply { + isEnabled = false + } chart.axisLeft.isEnabled = false chart.axisLeft.spaceTop = 40f diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt index 49afb8fab..2bba877ab 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartDualAxisActivity.kt @@ -47,12 +47,12 @@ class LineChartDualAxisActivity : DemoBase(), OnSeekBarChangeListener, OnChartVa binding.chart1.setOnChartValueSelectedListener(this) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) - binding.chart1.setDragDecelerationFrictionCoef(0.9f) + binding.chart1.dragDecelerationFrictionCoef = 0.9f // enable scaling and dragging binding.chart1.setDragEnabled(true) @@ -73,17 +73,16 @@ class LineChartDualAxisActivity : DemoBase(), OnSeekBarChangeListener, OnChartVa binding.chart1.animateX(1500) // get the legend (only possible after setting data) - val l = binding.chart1.legend - - // modify the legend ... - l.form = LegendForm.LINE - l.typeface = tfLight - l.textSize = 11f - l.textColor = Color.WHITE - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) + binding.chart1.legend?.apply { + form = LegendForm.LINE + typeface = tfLight + textSize = 11f + textColor = Color.WHITE + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + } // l.setYOffset(11f); val xAxis = binding.chart1.xAxis diff --git a/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt index eb80d58d8..19905fe0f 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/LineChartTimeActivity.kt @@ -41,12 +41,12 @@ class LineChartTimeActivity : DemoBase(), OnSeekBarChangeListener { binding.seekBarX.setOnSeekBarChangeListener(this) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) - binding.chart1.setDragDecelerationFrictionCoef(0.9f) + binding.chart1.dragDecelerationFrictionCoef = 0.9f // enable scaling and dragging binding.chart1.setDragEnabled(true) @@ -62,8 +62,9 @@ class LineChartTimeActivity : DemoBase(), OnSeekBarChangeListener { binding.seekBarX.progress = 100 // get the legend (only possible after setting data) - val l = binding.chart1.legend - l.isEnabled = false + binding.chart1.legend?.apply { + isEnabled = false + } val xAxis = binding.chart1.xAxis xAxis.position = XAxis.XAxisPosition.TOP_INSIDE diff --git a/app/src/main/kotlin/info/appdev/chartexample/ListViewBarChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/ListViewBarChartActivity.kt index 176be1c78..0911785c2 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/ListViewBarChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/ListViewBarChartActivity.kt @@ -73,7 +73,7 @@ class ListViewBarChartActivity : DemoBase() { data.setValueTypeface(tfLight) data.setValueTextColor(Color.BLACK) } - holder.chart!!.description.isEnabled = false + holder.chart!!.description?.isEnabled = false holder.chart!!.setDrawGridBackground(false) val xAxis = holder.chart!!.xAxis diff --git a/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt index 4d1fb0dec..d7035668e 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/MultiLineChartActivity.kt @@ -39,7 +39,7 @@ class MultiLineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartGestu binding.seekBarY.setOnSeekBarChangeListener(this) binding.chart1.setOnChartValueSelectedListener(this) binding.chart1.setDrawGridBackground(false) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setDrawBorders(false) binding.chart1.axisLeft.isEnabled = false @@ -61,7 +61,7 @@ class MultiLineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartGestu binding.seekBarX.progress = 20 binding.seekBarY.progress = 100 - binding.chart1.legend.apply { + binding.chart1.legend?.apply { verticalAlignment = Legend.LegendVerticalAlignment.TOP horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT orientation = Legend.LegendOrientation.VERTICAL diff --git a/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt b/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt index 8d9eb490e..0d7e85da0 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/PerformanceLineChart.kt @@ -29,7 +29,7 @@ class PerformanceLineChart : DemoBase(), OnSeekBarChangeListener { binding.chart1.setDrawGridBackground(false) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) @@ -78,8 +78,9 @@ class PerformanceLineChart : DemoBase(), OnSeekBarChangeListener { binding.chart1.setData(data) // get the legend (only possible after setting data) - val l = binding.chart1.legend - l.isEnabled = false + binding.chart1.legend?.apply { + isEnabled = false + } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { diff --git a/app/src/main/kotlin/info/appdev/chartexample/PieChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/PieChartActivity.kt index 064b8b992..3b3fd799d 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/PieChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/PieChartActivity.kt @@ -46,10 +46,10 @@ class PieChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSelect binding.seekBarY.setOnSeekBarChangeListener(this) binding.chart1.setUsePercentValues(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setExtraOffsets(5f, 10f, 5f, 5f) - binding.chart1.setDragDecelerationFrictionCoef(0.95f) + binding.chart1.dragDecelerationFrictionCoef = 0.95f binding.chart1.setCenterTextTypeface(tfLight) binding.chart1.centerText = generateCenterSpannableText() @@ -82,14 +82,15 @@ class PieChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSelect binding.chart1.animateY(1400, Easing.easeInOutQuad) // chart.spin(2000, 0, 360); - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(false) - l.xEntrySpace = 7f - l.yEntrySpace = 0f - l.yOffset = 0f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(false) + xEntrySpace = 7f + yEntrySpace = 0f + yOffset = 0f + } // entry label styling binding.chart1.setEntryLabelColor(Color.WHITE) diff --git a/app/src/main/kotlin/info/appdev/chartexample/PieChartRoundedActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/PieChartRoundedActivity.kt index dbaf606b0..9d0b286ef 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/PieChartRoundedActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/PieChartRoundedActivity.kt @@ -46,10 +46,10 @@ class PieChartRoundedActivity : DemoBase(), OnSeekBarChangeListener, OnChartValu binding.seekBarX.setOnSeekBarChangeListener(this) binding.seekBarY.setOnSeekBarChangeListener(this) binding.chart1.setUsePercentValues(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setExtraOffsets(5f, 10f, 5f, 5f) - binding.chart1.setDragDecelerationFrictionCoef(0.95f) + binding.chart1.dragDecelerationFrictionCoef = 0.95f binding.chart1.setCenterTextTypeface(tfLight) binding.chart1.centerText = generateCenterSpannableText() @@ -83,14 +83,15 @@ class PieChartRoundedActivity : DemoBase(), OnSeekBarChangeListener, OnChartValu binding.chart1.animateY(1400, Easing.easeInOutQuad) // chart.spin(2000, 0, 360); - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(false) - l.xEntrySpace = 7f - l.yEntrySpace = 0f - l.yOffset = 0f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(false) + xEntrySpace = 7f + yEntrySpace = 0f + yOffset = 0f + } // entry label styling binding.chart1.setEntryLabelColor(Color.WHITE) diff --git a/app/src/main/kotlin/info/appdev/chartexample/PiePolylineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/PiePolylineChartActivity.kt index 2d6f97f72..84d0e0f2c 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/PiePolylineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/PiePolylineChartActivity.kt @@ -45,10 +45,10 @@ class PiePolylineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartVal binding.seekBarY.setOnSeekBarChangeListener(this) binding.chart1.setUsePercentValues(true) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setExtraOffsets(5f, 10f, 5f, 5f) - binding.chart1.setDragDecelerationFrictionCoef(0.95f) + binding.chart1.dragDecelerationFrictionCoef = 0.95f tf = Typeface.createFromAsset(assets, "OpenSans-Regular.ttf") @@ -85,12 +85,13 @@ class PiePolylineChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartVal binding.chart1.animateY(1400, Easing.easeInOutQuad) // chart.spin(2000, 0, 360); - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(false) - l.isEnabled = false + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(false) + isEnabled = false + } } private fun setData(count: Int, range: Float) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/RadarChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/RadarChartActivity.kt index b75c4d9c6..f5b03ce4d 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/RadarChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/RadarChartActivity.kt @@ -33,7 +33,7 @@ class RadarChartActivity : DemoBase() { setContentView(binding.root) binding.chart1.setBackgroundColor(Color.rgb(60, 65, 82)) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.webLineWidth = 1f binding.chart1.webColor = Color.LTGRAY @@ -73,15 +73,16 @@ class RadarChartActivity : DemoBase() { yAxis.axisMaximum = 80f yAxis.setDrawLabels(false) - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.typeface = tfLight - l.xEntrySpace = 7f - l.yEntrySpace = 5f - l.textColor = Color.WHITE + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + typeface = tfLight + xEntrySpace = 7f + yEntrySpace = 5f + textColor = Color.WHITE + } } private fun setData() { diff --git a/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt index ac4b6e151..1ee76c327 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/RealtimeLineChartActivity.kt @@ -34,7 +34,7 @@ class RealtimeLineChartActivity : DemoBase(), OnChartValueSelectedListener { setContentView(binding.root) binding.chart1.setOnChartValueSelectedListener(this) - binding.chart1.description.isEnabled = true + binding.chart1.description?.isEnabled = true // enable touch gestures binding.chart1.setTouchEnabled(true) @@ -57,12 +57,11 @@ class RealtimeLineChartActivity : DemoBase(), OnChartValueSelectedListener { binding.chart1.setData(data) // get the legend (only possible after setting data) - val l = binding.chart1.legend - - // modify the legend ... - l.form = LegendForm.LINE - l.typeface = tfLight - l.textColor = Color.WHITE + binding.chart1.legend?.apply { + form = LegendForm.LINE + typeface = tfLight + textColor = Color.WHITE + } val xl = binding.chart1.xAxis xl.typeface = tfLight diff --git a/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt index 006300927..7e7605a60 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/ScatterChartActivity.kt @@ -36,7 +36,7 @@ class ScatterChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSe binding.seekBarX.setOnSeekBarChangeListener(this) binding.seekBarY.setOnSeekBarChangeListener(this) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false binding.chart1.setOnChartValueSelectedListener(this) binding.chart1.setDrawGridBackground(false) @@ -53,13 +53,14 @@ class ScatterChartActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSe binding.seekBarX.progress = 45 binding.seekBarY.progress = 100 - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(false) - l.typeface = tfLight - l.xOffset = 5f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(false) + typeface = tfLight + xOffset = 5f + } val yl = binding.chart1.axisLeft yl.typeface = tfLight diff --git a/app/src/main/kotlin/info/appdev/chartexample/ScrollViewActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/ScrollViewActivity.kt index ab93670c2..7449a61c8 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/ScrollViewActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/ScrollViewActivity.kt @@ -23,7 +23,7 @@ class ScrollViewActivity : DemoBase() { binding = ActivityScrollviewBinding.inflate(layoutInflater) setContentView(binding.root) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // scaling can now only be done on x- and y-axis separately binding.chart1.setPinchZoom(false) @@ -37,7 +37,7 @@ class ScrollViewActivity : DemoBase() { binding.chart1.axisLeft.setDrawGridLines(false) - binding.chart1.legend.isEnabled = false + binding.chart1.legend?.isEnabled = false setData(10) binding.chart1.setFitBars(true) diff --git a/app/src/main/kotlin/info/appdev/chartexample/SpecificPositionsLineChartActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/SpecificPositionsLineChartActivity.kt index 3b71cf6c7..d87191395 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/SpecificPositionsLineChartActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/SpecificPositionsLineChartActivity.kt @@ -49,7 +49,7 @@ class SpecificPositionsLineChartActivity : DemoBase(), OnSeekBarChangeListener, binding.chart1.setDrawGridBackground(false) // no description text - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // enable touch gestures binding.chart1.setTouchEnabled(true) @@ -115,10 +115,9 @@ class SpecificPositionsLineChartActivity : DemoBase(), OnSeekBarChangeListener, //mChart.invalidate(); // get the legend (only possible after setting data) - val l = binding.chart1.legend - - // modify the legend ... - l.form = LegendForm.LINE + binding.chart1.legend?.apply { + form = LegendForm.LINE + } } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt index 049a5c4fc..90b62fc07 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt @@ -43,7 +43,7 @@ class StackedBarActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSele binding.chart1.setOnChartValueSelectedListener(this) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // if more than 60 entries are displayed in the chart, no values will be // drawn @@ -74,14 +74,15 @@ class StackedBarActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSele binding.seekBarX.progress = 12 binding.seekBarY.progress = 100 - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.formSize = 8f - l.formToTextSpace = 4f - l.xEntrySpace = 6f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + formSize = 8f + formToTextSpace = 4f + xEntrySpace = 6f + } // chart.setDrawLegend(false); } diff --git a/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivityNegative.kt b/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivityNegative.kt index 9bd6786ae..4d87cb338 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivityNegative.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivityNegative.kt @@ -40,7 +40,7 @@ class StackedBarActivityNegative : DemoBase(), OnChartValueSelectedListener { binding.chart1.setOnChartValueSelectedListener(this) binding.chart1.setDrawGridBackground(false) - binding.chart1.description.isEnabled = false + binding.chart1.description?.isEnabled = false // scaling can now only be done on x- and y-axis separately binding.chart1.setPinchZoom(false) @@ -76,14 +76,15 @@ class StackedBarActivityNegative : DemoBase(), OnChartValueSelectedListener { } } - val l = binding.chart1.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.formSize = 8f - l.formToTextSpace = 4f - l.xEntrySpace = 6f + binding.chart1.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + formSize = 8f + formToTextSpace = 4f + xEntrySpace = 6f + } // IMPORTANT: When using negative values in stacked bars, always make sure the negative values are in the array first val values = ArrayList() diff --git a/app/src/main/kotlin/info/appdev/chartexample/compose/HorizontalBarComposeActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/compose/HorizontalBarComposeActivity.kt index 78b018def..706ec8bb9 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/compose/HorizontalBarComposeActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/compose/HorizontalBarComposeActivity.kt @@ -290,7 +290,7 @@ class HorizontalBarComposeActivity : DemoBaseCompose() { chart.setDrawBarShadow(false) chart.setDrawValueAboveBar(true) - chart.description.isEnabled = false + chart.description?.isEnabled = false chart.setMaxVisibleValueCount(60) chart.setPinchZoom(false) chart.setDrawGridBackground(false) @@ -320,13 +320,14 @@ class HorizontalBarComposeActivity : DemoBaseCompose() { chart.setFitBars(true) chart.animateY(2500) - val l = chart.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM - l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT - l.orientation = Legend.LegendOrientation.HORIZONTAL - l.setDrawInside(false) - l.formSize = 8f - l.xEntrySpace = 4f + chart.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM + horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT + orientation = Legend.LegendOrientation.HORIZONTAL + setDrawInside(false) + formSize = 8f + xEntrySpace = 4f + } } private fun setData(count: Int, range: Float) { diff --git a/app/src/main/kotlin/info/appdev/chartexample/fragments/BarChartFrag.kt b/app/src/main/kotlin/info/appdev/chartexample/fragments/BarChartFrag.kt index 67e7cfa73..872563c23 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/fragments/BarChartFrag.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/fragments/BarChartFrag.kt @@ -23,7 +23,7 @@ class BarChartFrag : SimpleFragment(), OnChartGestureListener { // create a new chart object chart = BarChart(requireActivity()) - chart!!.description.isEnabled = false + chart!!.description?.isEnabled = false chart!!.onChartGestureListener = this val mv = MyMarkerView(activity, R.layout.custom_marker_view) @@ -37,8 +37,9 @@ class BarChartFrag : SimpleFragment(), OnChartGestureListener { chart!!.setData(generateBarData(1, 20000f)) - val l = chart!!.legend - l.typeface = tf + chart!!.legend?.apply { + typeface = tf + } val leftAxis = chart!!.axisLeft leftAxis.typeface = tf diff --git a/app/src/main/kotlin/info/appdev/chartexample/fragments/ComplexityFragment.kt b/app/src/main/kotlin/info/appdev/chartexample/fragments/ComplexityFragment.kt index cc48c3127..9a39344d5 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/fragments/ComplexityFragment.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/fragments/ComplexityFragment.kt @@ -17,7 +17,7 @@ class ComplexityFragment : SimpleFragment() { chart = v.findViewById(R.id.lineChart1) - chart!!.description.isEnabled = false + chart!!.description?.isEnabled = false chart!!.setDrawGridBackground(false) @@ -26,8 +26,9 @@ class ComplexityFragment : SimpleFragment() { val tf = Typeface.createFromAsset(requireContext().assets, "OpenSans-Light.ttf") - val l = chart!!.legend - l.typeface = tf + chart!!.legend?.apply { + typeface = tf + } val leftAxis = chart!!.axisLeft leftAxis.typeface = tf diff --git a/app/src/main/kotlin/info/appdev/chartexample/fragments/PieChartFrag.kt b/app/src/main/kotlin/info/appdev/chartexample/fragments/PieChartFrag.kt index 8b86a1b59..90725a1a3 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/fragments/PieChartFrag.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/fragments/PieChartFrag.kt @@ -21,7 +21,7 @@ class PieChartFrag : SimpleFragment() { val v = inflater.inflate(R.layout.frag_simple_pie, container, false) chart = v.findViewById(R.id.pieChart1) - chart!!.description.isEnabled = false + chart!!.description?.isEnabled = false val tf = Typeface.createFromAsset(requireContext().assets, "OpenSans-Light.ttf") @@ -34,11 +34,12 @@ class PieChartFrag : SimpleFragment() { chart!!.holeRadius = 45f chart!!.transparentCircleRadius = 50f - val l = chart!!.legend - l.verticalAlignment = Legend.LegendVerticalAlignment.TOP - l.horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT - l.orientation = Legend.LegendOrientation.VERTICAL - l.setDrawInside(false) + chart!!.legend?.apply { + verticalAlignment = Legend.LegendVerticalAlignment.TOP + horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT + orientation = Legend.LegendOrientation.VERTICAL + setDrawInside(false) + } chart!!.setData(generatePieData()) diff --git a/app/src/main/kotlin/info/appdev/chartexample/fragments/ScatterChartFrag.kt b/app/src/main/kotlin/info/appdev/chartexample/fragments/ScatterChartFrag.kt index 04c384b08..7860c75d6 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/fragments/ScatterChartFrag.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/fragments/ScatterChartFrag.kt @@ -18,7 +18,7 @@ class ScatterChartFrag : SimpleFragment() { val v = inflater.inflate(R.layout.frag_simple_scatter, container, false) chart = v.findViewById(R.id.scatterChart1) - chart!!.description.isEnabled = false + chart!!.description?.isEnabled = false val tf = Typeface.createFromAsset(requireContext().assets, "OpenSans-Light.ttf") @@ -40,14 +40,15 @@ class ScatterChartFrag : SimpleFragment() { rightAxis.typeface = tf rightAxis.setDrawGridLines(false) - val l = chart!!.legend - l.isWordWrapEnabled = true - l.typeface = tf - l.formSize = 14f - l.textSize = 9f + chart!!.legend?.apply { + isWordWrapEnabled = true + typeface = tf + formSize = 14f + textSize = 9f + // increase the space between legend & bottom and legend & content + yOffset = 13f + } - // increase the space between legend & bottom and legend & content - l.yOffset = 13f chart!!.extraBottomOffset = 16f return v diff --git a/app/src/main/kotlin/info/appdev/chartexample/fragments/SineCosineFragment.kt b/app/src/main/kotlin/info/appdev/chartexample/fragments/SineCosineFragment.kt index 3ef3f7bb6..cb8888e0f 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/fragments/SineCosineFragment.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/fragments/SineCosineFragment.kt @@ -17,7 +17,7 @@ class SineCosineFragment : SimpleFragment() { chart = v.findViewById(R.id.lineChart1) - chart!!.description.isEnabled = false + chart!!.description?.isEnabled = false chart!!.setDrawGridBackground(false) @@ -26,8 +26,9 @@ class SineCosineFragment : SimpleFragment() { val tf = Typeface.createFromAsset(requireContext().assets, "OpenSans-Light.ttf") - val l = chart!!.legend - l.typeface = tf + chart!!.legend?.apply { + typeface = tf + } val leftAxis = chart!!.axisLeft leftAxis.typeface = tf diff --git a/app/src/main/kotlin/info/appdev/chartexample/listviewitems/BarChartItem.kt b/app/src/main/kotlin/info/appdev/chartexample/listviewitems/BarChartItem.kt index 2e0811c17..d1e273c2b 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/listviewitems/BarChartItem.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/listviewitems/BarChartItem.kt @@ -36,7 +36,7 @@ class BarChartItem(cd: ChartData<*>, c: Context) : ChartItem(cd) { } // apply styling - holder.chart!!.description.isEnabled = false + holder.chart!!.description?.isEnabled = false holder.chart!!.setDrawGridBackground(false) holder.chart!!.setDrawBarShadow(false) diff --git a/app/src/main/kotlin/info/appdev/chartexample/listviewitems/LineChartItem.kt b/app/src/main/kotlin/info/appdev/chartexample/listviewitems/LineChartItem.kt index 74a71fa04..49e18883d 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/listviewitems/LineChartItem.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/listviewitems/LineChartItem.kt @@ -37,7 +37,7 @@ class LineChartItem(cd: ChartData<*>, c: Context) : ChartItem(cd) { // apply styling // holder.chart.setValueTypeface(mTf); - holder.chart!!.description.isEnabled = false + holder.chart!!.description?.isEnabled = false holder.chart!!.setDrawGridBackground(false) val xAxis = holder.chart!!.xAxis diff --git a/app/src/main/kotlin/info/appdev/chartexample/listviewitems/PieChartItem.kt b/app/src/main/kotlin/info/appdev/chartexample/listviewitems/PieChartItem.kt index 2475f049e..0d821ed54 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/listviewitems/PieChartItem.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/listviewitems/PieChartItem.kt @@ -48,7 +48,7 @@ class PieChartItem(cd: ChartData<*>, c: Context) : ChartItem(cd) { } // apply styling - holder.chart!!.description.isEnabled = false + holder.chart!!.description?.isEnabled = false holder.chart!!.holeRadius = 52f holder.chart!!.transparentCircleRadius = 57f holder.chart!!.centerText = centerText