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 aa990e1e1..2e547de25 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 @@ -80,20 +80,22 @@ open class BarChart : BarLineChartBase, BarDataProvider { } protected override fun calcMinMax() { - if (mFitBars) { - mXAxis.calculate(mData.xMin - mData.barWidth / 2f, mData.xMax + mData.barWidth / 2f) - } else { - mXAxis.calculate(mData.xMin, mData.xMax) - } - - // calculate axis range (min / max) according to provided data - mAxisLeft.calculate(mData.getYMin(YAxis.AxisDependency.LEFT), mData.getYMax(YAxis.AxisDependency.LEFT)) - mAxisRight.calculate( - mData.getYMin(YAxis.AxisDependency.RIGHT), mData.getYMax( - YAxis.AxisDependency - .RIGHT + mData?.let { barData -> + if (mFitBars) { + mXAxis.calculate(barData.xMin - barData.barWidth / 2f, barData.xMax + barData.barWidth / 2f) + } else { + mXAxis.calculate(barData.xMin, barData.xMax) + } + + // calculate axis range (min / max) according to provided data + mAxisLeft.calculate(barData.getYMin(YAxis.AxisDependency.LEFT), barData.getYMax(YAxis.AxisDependency.LEFT)) + mAxisRight.calculate( + barData.getYMin(YAxis.AxisDependency.RIGHT), barData.getYMax( + YAxis.AxisDependency + .RIGHT + ) ) - ) + } } /** @@ -134,26 +136,28 @@ open class BarChart : BarLineChartBase, BarDataProvider { * The rect will be assigned Float.MIN_VALUE in all locations if the Entry could not be found in the charts data. */ open fun getBarBounds(barEntry: BarEntry, outputRect: RectF) { - val set = mData.getDataSetForEntry(barEntry) + mData?.let { barData -> + val set = barData.getDataSetForEntry(barEntry) - if (set == null) { - outputRect.set(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE) - return - } + if (set == null) { + outputRect.set(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE) + return + } - val y = barEntry.y - val x = barEntry.x + val y = barEntry.y + val x = barEntry.x - val barWidth = mData.barWidth + val barWidth = barData.barWidth - val left = x - barWidth / 2f - val right = x + barWidth / 2f - val top = if (y >= 0) y else 0f - val bottom = if (y <= 0) y else 0f + val left = x - barWidth / 2f + val right = x + barWidth / 2f + val top = if (y >= 0) y else 0f + val bottom = if (y <= 0) y else 0f - outputRect.set(left, top, right, bottom) + outputRect.set(left, top, right, bottom) - getTransformer(set.axisDependency)!!.rectValueToPixel(outputRect) + getTransformer(set.axisDependency)!!.rectValueToPixel(outputRect) + } } /** @@ -182,7 +186,7 @@ open class BarChart : BarLineChartBase, BarDataProvider { highlightValue(Highlight(x, dataSetIndex, stackIndex), false) } - override val barData: BarData + override val barData: BarData? get() = mData /** @@ -206,7 +210,7 @@ open class BarChart : BarLineChartBase, BarDataProvider { * @param barSpace the space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f */ fun groupBars(fromX: Float, groupSpace: Float, barSpace: Float) { - barData.groupBars(fromX, groupSpace, barSpace) + barData?.groupBars(fromX, groupSpace, barSpace) notifyDataSetChanged() } @@ -222,28 +226,29 @@ open class BarChart : BarLineChartBase, BarDataProvider { } override fun getAccessibilityDescription(): String { - val barData = 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 - ) + 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 "" } } 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 index 6f55fc899..50796dc61 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.java +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.java @@ -48,6 +48,7 @@ import java.util.List; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Baseclass of all Chart-Views. @@ -68,6 +69,7 @@ public abstract class Chart + val set = data.getDataSetForEntry(barEntry) - val y = barEntry.y - val x = barEntry.x + val y = barEntry.y + val x = barEntry.x - val barWidth = mData.barWidth + val barWidth = data.barWidth - val top = x - barWidth / 2f - val bottom = x + barWidth / 2f - val left = if (y >= 0) y else 0f - val right = if (y <= 0) y else 0f + val top = x - barWidth / 2f + val bottom = x + barWidth / 2f + val left = if (y >= 0) y else 0f + val right = if (y <= 0) y else 0f - bounds.set(left, top, right, bottom) + outputRect.set(left, top, right, bottom) - getTransformer(set!!.axisDependency)!!.rectValueToPixel(bounds) + getTransformer(set!!.axisDependency)!!.rectValueToPixel(outputRect) + } } protected var mGetPositionBuffer: FloatArray = FloatArray(2) 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 6c77a1fb9..3e0803841 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 @@ -172,26 +172,23 @@ class PieChart : PieRadarChartBase { override fun calculateOffsets() { super.calculateOffsets() - // prevent nullpointer when no data set - if (mData == null) return - - val diameter = diameter - val radius = diameter / 2f - - val c = centerOffsets - - val shift = mData.dataSet.selectionShift - - // create the circle box that will contain the pie-chart (the bounds of - // the pie-chart) - circleBox.set( - c.x - radius + shift, - c.y - radius + shift, - c.x + radius - shift, - c.y + radius - shift - ) + mData?.let { data -> + val diameter = diameter + val radius = diameter / 2f + + val shift = data.dataSet.selectionShift + + // create the circle box that will contain the pie-chart (the bounds of + // the pie-chart) + circleBox.set( + centerOffsets.x - radius + shift, + centerOffsets.y - radius + shift, + centerOffsets.x + radius - shift, + centerOffsets.y + radius - shift + ) - recycleInstance(c) + recycleInstance(centerOffsets) + } } override fun calcMinMax() { @@ -241,76 +238,78 @@ class PieChart : PieRadarChartBase { * calculates the needed angles for the chart slices */ private fun calcAngles() { - val entryCount = mData.entryCount - - if (drawAngles.size != entryCount) { - this.drawAngles = FloatArray(entryCount) - } else { - for (i in 0.. + val entryCount = data.entryCount + + if (drawAngles.size != entryCount) { + this.drawAngles = FloatArray(entryCount) + } else { + for (i in 0.. { /** * calculates the needed angle for a given value */ - /** - * calculates the needed angle for a given value - */ - private fun calcAngle(value: Float, yValueSum: Float = mData.yValueSum): Float { + private fun calcAngle(value: Float, yValueSum: Float): Float { return value / yValueSum * mMaxAngle } @@ -362,10 +358,10 @@ class PieChart : PieRadarChartBase { * Returns the index of the DataSet this x-index belongs to. */ fun getDataSetIndexForIndex(xIndex: Int): Int { - val dataSets = mData.dataSets + val dataSets = mData?.dataSets for (i in dataSets!!.indices) { - if (dataSets.get(i).getEntryForXValue(xIndex.toFloat(), Float.NaN) != null) return i + if (dataSets[i].getEntryForXValue(xIndex.toFloat(), Float.NaN) != null) return i } return -1 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 3708aa3ee..102806bce 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 @@ -110,22 +110,23 @@ class RadarChart : PieRadarChartBase { override fun calcMinMax() { super.calcMinMax() - - mYAxis!!.calculate(mData.getYMin(AxisDependency.LEFT), mData.getYMax(AxisDependency.LEFT)) - mXAxis.calculate(0f, mData.maxEntryCountSet!!.entryCount.toFloat()) + mData?.let { data -> + mYAxis!!.calculate(data.getYMin(AxisDependency.LEFT), data.getYMax(AxisDependency.LEFT)) + mXAxis.calculate(0f, data.maxEntryCountSet!!.entryCount.toFloat()) + } } override fun notifyDataSetChanged() { - if (mData == null) return + mData?.let { data -> + calcMinMax() - calcMinMax() + mYAxisRenderer!!.computeAxis(mYAxis!!.mAxisMinimum, mYAxis!!.mAxisMaximum, mYAxis!!.isInverted) + mXAxisRenderer!!.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false) - mYAxisRenderer!!.computeAxis(mYAxis!!.mAxisMinimum, mYAxis!!.mAxisMaximum, mYAxis!!.isInverted) - mXAxisRenderer!!.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false) + if (mLegend != null && !mLegend.isLegendCustom) mLegendRenderer.computeLegend(data) - if (mLegend != null && !mLegend.isLegendCustom) mLegendRenderer.computeLegend(mData) - - calculateOffsets() + calculateOffsets() + } } protected override fun onDraw(canvas: Canvas) { @@ -175,7 +176,7 @@ class RadarChart : PieRadarChartBase { * Returns the angle that each slice in the radar chart occupies. * */ - get() = 360f / mData.maxEntryCountSet!!.entryCount.toFloat() + get() = 360f / mData?.maxEntryCountSet!!.entryCount.toFloat() val isCustomLayerColorEnable: Boolean @@ -202,7 +203,7 @@ class RadarChart : PieRadarChartBase { val sliceangle = this.sliceAngle - val max = mData.maxEntryCountSet!!.entryCount + val max = mData?.maxEntryCountSet!!.entryCount var index = 0 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 9e5bfd9fe..e41887dd7 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 @@ -28,7 +28,7 @@ class ScatterChart : BarLineChartBase, ScatterDataProvider { xAxis.spaceMax = 0.5f } - override val scatterData: ScatterData + override val scatterData: ScatterData? get() = mData /** diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/BarHighlighter.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/BarHighlighter.kt index da33fd8b8..9be546a73 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/BarHighlighter.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/BarHighlighter.kt @@ -12,16 +12,16 @@ open class BarHighlighter(barDataProvider: BarDataProvider) : ChartHighlighter - if (set.isStacked()) { - return getStackedHighlight( - high, - set, - pos.x.toFloat(), - pos.y.toFloat() - ) + provider.barData?.let { barData -> + barData.getDataSetByIndex(high.dataSetIndex)?.let { set -> + if (set.isStacked()) { + return getStackedHighlight( + high, + set, + pos.x.toFloat(), + pos.y.toFloat() + ) + } } } MPPointD.recycleInstance(pos) diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/HorizontalBarHighlighter.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/HorizontalBarHighlighter.kt index 1bc4fb7a1..bea245f05 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/HorizontalBarHighlighter.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/highlight/HorizontalBarHighlighter.kt @@ -9,25 +9,27 @@ import kotlin.math.abs class HorizontalBarHighlighter(dataProvider: BarDataProvider) : BarHighlighter(dataProvider) { override fun getHighlight(x: Float, y: Float): Highlight? { - val barData = provider.barData + provider.barData?.let { barData -> - val pos = getValsForTouch(y, x) + val pos = getValsForTouch(y, x) - val high = getHighlightForX(pos.y.toFloat(), y, x) ?: return null + val high = getHighlightForX(pos.y.toFloat(), y, x) ?: return null - val set = barData.getDataSetByIndex(high.dataSetIndex) - if (set != null && set.isStacked()) { - return getStackedHighlight( - high, - set, - pos.y.toFloat(), - pos.x.toFloat() - ) - } + val set = barData.getDataSetByIndex(high.dataSetIndex) + if (set != null && set.isStacked()) { + return getStackedHighlight( + high, + set, + pos.y.toFloat(), + pos.x.toFloat() + ) + } - MPPointD.recycleInstance(pos) + MPPointD.recycleInstance(pos) - return high + return high + } + return null } override fun buildHighlights(set: IDataSet<*>, dataSetIndex: Int, xVal: Float, rounding: DataSet.Rounding?): MutableList { diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/BarDataProvider.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/BarDataProvider.kt index c41357da7..886f3255e 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/BarDataProvider.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/interfaces/dataprovider/BarDataProvider.kt @@ -4,7 +4,7 @@ import com.github.mikephil.charting.data.BarData import com.github.mikephil.charting.interfaces.dataprovider.base.BarLineScatterCandleBubbleDataProvider interface BarDataProvider : BarLineScatterCandleBubbleDataProvider { - val barData: BarData + val barData: BarData? var isDrawBarShadowEnabled: Boolean var isDrawValueAboveBarEnabled: Boolean var isHighlightFullBarEnabled: Boolean diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/listener/BarLineChartTouchListener.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/listener/BarLineChartTouchListener.kt index e3eb2d8c8..c3a2f9996 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/listener/BarLineChartTouchListener.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/listener/BarLineChartTouchListener.kt @@ -25,11 +25,11 @@ import kotlin.math.sqrt */ @Suppress("MemberVisibilityCanBePrivate") class BarLineChartTouchListener( - chart: BarLineChartBase>>, + chart: BarLineChartBase>>, touchMatrix: Matrix, dragTriggerDistance: Float ) : - ChartTouchListener>>>(chart) { + ChartTouchListener>>>(chart) { /** * the original touch-matrix from the chart */ diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/BarChartRenderer.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/BarChartRenderer.kt index 779871098..cee3cd3d2 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/BarChartRenderer.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/BarChartRenderer.kt @@ -60,7 +60,7 @@ open class BarChartRenderer( val barData = dataProvider.barData barBuffers = mutableListOf() - barData.dataSets?.forEach { + barData?.dataSets?.forEach { barBuffers.add( BarBuffer( it.entryCount * 4 * (if (it.isStacked) it.stackSize else 1), @@ -75,14 +75,14 @@ open class BarChartRenderer( initBuffers() } - val barData = dataProvider.barData - - for (i in 0.. + for (i in 0.. - val barWidth = barData.barWidth - val barWidthHalf = barWidth / 2.0f - var x: Float + val barWidth = barData.barWidth + val barWidthHalf = barWidth / 2.0f + var x: Float - var i = 0 - val count = min((ceil(((dataSet.entryCount).toFloat() * phaseX).toDouble())).toInt().toDouble(), dataSet.entryCount.toDouble()).toInt() - while (i < count) { - val barEntry = dataSet.getEntryForIndex(i) + var i = 0 + val count = min((ceil(((dataSet.entryCount).toFloat() * phaseX).toDouble())).toInt().toDouble(), dataSet.entryCount.toDouble()).toInt() + while (i < count) { + val barEntry = dataSet.getEntryForIndex(i) - barEntry?.let { - x = barEntry.x + barEntry?.let { + x = barEntry.x - barShadowRectBuffer.left = x - barWidthHalf - barShadowRectBuffer.right = x + barWidthHalf + barShadowRectBuffer.left = x - barWidthHalf + barShadowRectBuffer.right = x + barWidthHalf - trans!!.rectValueToPixel(barShadowRectBuffer) - } - if (!viewPortHandler.isInBoundsLeft(barShadowRectBuffer.right)) { - i++ - continue - } + trans!!.rectValueToPixel(barShadowRectBuffer) + } + if (!viewPortHandler.isInBoundsLeft(barShadowRectBuffer.right)) { + i++ + continue + } - if (!viewPortHandler.isInBoundsRight(barShadowRectBuffer.left)) { - break - } + if (!viewPortHandler.isInBoundsRight(barShadowRectBuffer.left)) { + break + } - barShadowRectBuffer.top = viewPortHandler.contentTop() - barShadowRectBuffer.bottom = viewPortHandler.contentBottom() + barShadowRectBuffer.top = viewPortHandler.contentTop() + barShadowRectBuffer.bottom = viewPortHandler.contentBottom() - if (drawRoundedBars) { - canvas.drawRoundRect(barShadowRectBuffer, roundedBarRadius, roundedBarRadius, shadowPaint) - } else { - canvas.drawRect(barShadowRectBuffer, shadowPaint) + if (drawRoundedBars) { + canvas.drawRoundRect(barShadowRectBuffer, roundedBarRadius, roundedBarRadius, shadowPaint) + } else { + canvas.drawRect(barShadowRectBuffer, shadowPaint) + } + i++ } - i++ } } @@ -164,7 +165,7 @@ open class BarChartRenderer( setPhases(phaseX, phaseY) setDataSet(index) setInverted(dataProvider.isInverted(dataSet.axisDependency)) - setBarWidth(dataProvider.barData.barWidth) + dataProvider.barData?.let { setBarWidth(it.barWidth) } feed(dataSet) } trans!!.pointValuesToPixel(buffer.buffer) @@ -255,132 +256,74 @@ open class BarChartRenderer( // if values are drawn if (isDrawingValuesAllowed(dataProvider)) { - val dataSets = dataProvider.barData.dataSets + val dataSets = dataProvider.barData?.dataSets val valueOffsetPlus = 4.5f.convertDpToPixel() var posOffset: Float var negOffset: Float val drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled - for (i in 0.. + for (i in 0..= 0) (buffer.buffer[j + 1] + posOffset) else (buffer.buffer[j + 3] + negOffset), - dataSet.getValueTextColor(j / 4) - ) + if (!viewPortHandler.isInBoundsRight(x)) { + break } - if (barEntry.icon != null && dataSet.isDrawIcons) { - val icon = barEntry.icon - - var px = x - var py = if (value >= 0) (buffer.buffer[j + 1] + posOffset) else (buffer.buffer[j + 3] + negOffset) - - px += iconsOffset.x - py += iconsOffset.y - - icon?.let { - Utils.drawImage( - canvas, - it, - px.toInt(), - py.toInt() - ) - } + if (!viewPortHandler.isInBoundsY(buffer.buffer[j + 1]) + || !viewPortHandler.isInBoundsLeft(x) + ) { + j += 4 + continue } - } - j += 4 - } - // if we have stacks - } else { - val trans = dataProvider.getTransformer(dataSet.axisDependency) - - var bufferIndex = 0 - var index = 0 - - while (index < dataSet.entryCount * animator.phaseX) { - val barEntry = dataSet.getEntryForIndex(index) - barEntry?.let { - val vals = barEntry.yVals - val x = (buffer!!.buffer[bufferIndex] + buffer.buffer[bufferIndex + 2]) / 2f - val color = dataSet.getValueTextColor(index) - - // we still draw stacked bars, but there is one - // non-stacked - // in between - if (vals == null) { - if (!viewPortHandler.isInBoundsRight(x)) { - break - } - - if (!viewPortHandler.isInBoundsY(buffer.buffer[bufferIndex + 1]) - || !viewPortHandler.isInBoundsLeft(x) - ) { - continue - } + val barEntry = dataSet.getEntryForIndex(j / 4) + barEntry?.let { + val value = barEntry.y if (dataSet.isDrawValues) { drawValue( - canvas, dataSet.valueFormatter, barEntry.y, barEntry, i, x, - buffer.buffer[bufferIndex + 1] + (if (barEntry.y >= 0) - posOffset else negOffset), - color + canvas, dataSet.valueFormatter, value, barEntry, i, x, + if (value >= 0) (buffer.buffer[j + 1] + posOffset) else (buffer.buffer[j + 3] + negOffset), + dataSet.getValueTextColor(j / 4) ) } @@ -388,8 +331,7 @@ open class BarChartRenderer( val icon = barEntry.icon var px = x - var py = buffer.buffer[bufferIndex + 1] + - (if (barEntry.y >= 0) posOffset else negOffset) + var py = if (value >= 0) (buffer.buffer[j + 1] + posOffset) else (buffer.buffer[j + 3] + negOffset) px += iconsOffset.x py += iconsOffset.y @@ -403,69 +345,43 @@ open class BarChartRenderer( ) } } + } + j += 4 + } - // draw stack values - } else { - val transformed = FloatArray(vals.size * 2) - - var posY = 0f - var negY = -barEntry.negativeSum - - run { - var k = 0 - var idx = 0 - while (k < transformed.size) { - val value = vals[idx] - val y: Float - - if (value == 0.0f && (posY == 0.0f || negY == 0.0f)) { - // Take care of the situation of a 0.0 value, which overlaps a non-zero bar - y = value - } else if (value >= 0.0f) { - posY += value - y = posY - } else { - y = negY - negY -= value - } + // if we have stacks + } else { + val trans = dataProvider.getTransformer(dataSet.axisDependency) - transformed[k + 1] = y * phaseY - k += 2 - idx++ - } - } + var bufferIndex = 0 + var index = 0 - trans!!.pointValuesToPixel(transformed) - - var k = 0 - while (k < transformed.size) { - val `val` = vals[k / 2] - val drawBelow = - (`val` == 0.0f && negY == 0.0f && posY > 0.0f) || - `val` < 0.0f - val y = (transformed[k + 1] - + (if (drawBelow) negOffset else posOffset)) + while (index < dataSet.entryCount * animator.phaseX) { + val barEntry = dataSet.getEntryForIndex(index) + barEntry?.let { + val vals = barEntry.yVals + val x = (buffer!!.buffer[bufferIndex] + buffer.buffer[bufferIndex + 2]) / 2f + val color = dataSet.getValueTextColor(index) + // we still draw stacked bars, but there is one + // non-stacked + // in between + if (vals == null) { if (!viewPortHandler.isInBoundsRight(x)) { break } - if (!viewPortHandler.isInBoundsY(y) + if (!viewPortHandler.isInBoundsY(buffer.buffer[bufferIndex + 1]) || !viewPortHandler.isInBoundsLeft(x) ) { - k += 2 continue } if (dataSet.isDrawValues) { drawValue( - canvas, - dataSet.valueFormatter, - vals[k / 2], - barEntry, - i, - x, - y, + canvas, dataSet.valueFormatter, barEntry.y, barEntry, i, x, + buffer.buffer[bufferIndex + 1] + (if (barEntry.y >= 0) + posOffset else negOffset), color ) } @@ -473,26 +389,113 @@ open class BarChartRenderer( if (barEntry.icon != null && dataSet.isDrawIcons) { val icon = barEntry.icon + var px = x + var py = buffer.buffer[bufferIndex + 1] + + (if (barEntry.y >= 0) posOffset else negOffset) + + px += iconsOffset.x + py += iconsOffset.y + icon?.let { Utils.drawImage( canvas, it, - (x + iconsOffset.x).toInt(), - (y + iconsOffset.y).toInt() + px.toInt(), + py.toInt() ) } } - k += 2 + + // draw stack values + } else { + val transformed = FloatArray(vals.size * 2) + + var posY = 0f + var negY = -barEntry.negativeSum + + run { + var k = 0 + var idx = 0 + while (k < transformed.size) { + val value = vals[idx] + val y: Float + + if (value == 0.0f && (posY == 0.0f || negY == 0.0f)) { + // Take care of the situation of a 0.0 value, which overlaps a non-zero bar + y = value + } else if (value >= 0.0f) { + posY += value + y = posY + } else { + y = negY + negY -= value + } + + transformed[k + 1] = y * phaseY + k += 2 + idx++ + } + } + + trans!!.pointValuesToPixel(transformed) + + var k = 0 + while (k < transformed.size) { + val `val` = vals[k / 2] + val drawBelow = + (`val` == 0.0f && negY == 0.0f && posY > 0.0f) || + `val` < 0.0f + val y = (transformed[k + 1] + + (if (drawBelow) negOffset else posOffset)) + + if (!viewPortHandler.isInBoundsRight(x)) { + break + } + + if (!viewPortHandler.isInBoundsY(y) + || !viewPortHandler.isInBoundsLeft(x) + ) { + k += 2 + continue + } + + if (dataSet.isDrawValues) { + drawValue( + canvas, + dataSet.valueFormatter, + vals[k / 2], + barEntry, + i, + x, + y, + color + ) + } + + if (barEntry.icon != null && dataSet.isDrawIcons) { + val icon = barEntry.icon + + icon?.let { + Utils.drawImage( + canvas, + it, + (x + iconsOffset.x).toInt(), + (y + iconsOffset.y).toInt() + ) + } + } + k += 2 + } } - } - bufferIndex = if (vals == null) bufferIndex + 4 else bufferIndex + 4 * vals.size + bufferIndex = if (vals == null) bufferIndex + 4 else bufferIndex + 4 * vals.size + } + index++ } - index++ } - } - MPPointF.recycleInstance(iconsOffset) + MPPointF.recycleInstance(iconsOffset) + } } } } @@ -501,7 +504,7 @@ open class BarChartRenderer( val barData = dataProvider.barData for (high in indices) { - val set = barData.getDataSetByIndex(high.dataSetIndex) + val set = barData?.getDataSetByIndex(high.dataSetIndex) if (set == null || !set.isHighlightEnabled) { continue diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.kt index 3d511ff96..ac5f8cc1f 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.kt @@ -27,16 +27,17 @@ open class HorizontalBarChartRenderer( viewPortHandler: ViewPortHandler ) : BarChartRenderer(chart, animator, viewPortHandler) { override fun initBuffers() { - val barData = dataProvider.barData - barBuffers = arrayOfNulls(barData.dataSetCount).toMutableList() - - for (i in barBuffers.indices) { - val set = barData.getDataSetByIndex(i) - set?.let { - barBuffers[i] = HorizontalBarBuffer( - it.entryCount * 4 * (if (set.isStacked) set.stackSize else 1), - barData.dataSetCount, set.isStacked - ) + dataProvider.barData?.let { barData -> + barBuffers = arrayOfNulls(barData.dataSetCount).toMutableList() + + for (i in barBuffers.indices) { + val set = barData.getDataSetByIndex(i) + set?.let { + barBuffers[i] = HorizontalBarBuffer( + it.entryCount * 4 * (if (set.isStacked) set.stackSize else 1), + barData.dataSetCount, set.isStacked + ) + } } } } @@ -62,40 +63,41 @@ open class HorizontalBarChartRenderer( if (dataProvider.isDrawBarShadowEnabled) { shadowPaint.color = dataSet.barShadowColor - val barData = dataProvider.barData + dataProvider.barData?.let { barData -> - val barWidth = barData.barWidth - val barWidthHalf = barWidth / 2.0f - var x: Float + val barWidth = barData.barWidth + val barWidthHalf = barWidth / 2.0f + var x: Float - var i = 0 - val count = min((ceil(((dataSet.entryCount).toFloat() * phaseX).toDouble())).toInt().toDouble(), dataSet.entryCount.toDouble()).toInt() - while (i < count - ) { - val barEntry = dataSet.getEntryForIndex(i) - barEntry?.let { - x = it.x + var i = 0 + val count = min((ceil(((dataSet.entryCount).toFloat() * phaseX).toDouble())).toInt().toDouble(), dataSet.entryCount.toDouble()).toInt() + while (i < count + ) { + val barEntry = dataSet.getEntryForIndex(i) + barEntry?.let { + x = it.x - mBarShadowRectBuffer.top = x - barWidthHalf - mBarShadowRectBuffer.bottom = x + barWidthHalf + mBarShadowRectBuffer.top = x - barWidthHalf + mBarShadowRectBuffer.bottom = x + barWidthHalf - trans!!.rectValueToPixel(mBarShadowRectBuffer) + trans!!.rectValueToPixel(mBarShadowRectBuffer) - if (!viewPortHandler.isInBoundsTop(mBarShadowRectBuffer.bottom)) { - i++ - continue - } + if (!viewPortHandler.isInBoundsTop(mBarShadowRectBuffer.bottom)) { + i++ + continue + } - if (!viewPortHandler.isInBoundsBottom(mBarShadowRectBuffer.top)) { - break - } + if (!viewPortHandler.isInBoundsBottom(mBarShadowRectBuffer.top)) { + break + } - mBarShadowRectBuffer.left = viewPortHandler.contentLeft() - mBarShadowRectBuffer.right = viewPortHandler.contentRight() + mBarShadowRectBuffer.left = viewPortHandler.contentLeft() + mBarShadowRectBuffer.right = viewPortHandler.contentRight() - canvas.drawRect(mBarShadowRectBuffer, shadowPaint) + canvas.drawRect(mBarShadowRectBuffer, shadowPaint) + } + i++ } - i++ } } @@ -104,7 +106,7 @@ open class HorizontalBarChartRenderer( buffer.setPhases(phaseX, phaseY) buffer.setDataSet(index) buffer.setInverted(dataProvider.isInverted(dataSet.axisDependency)) - buffer.setBarWidth(dataProvider.barData.barWidth) + dataProvider.barData?.let { buffer.setBarWidth(it.barWidth) } buffer.feed(dataSet) @@ -169,144 +171,69 @@ open class HorizontalBarChartRenderer( override fun drawValues(canvas: Canvas) { // if values are drawn if (isDrawingValuesAllowed(dataProvider)) { - val dataSets = dataProvider.barData.dataSets + val dataSets = dataProvider.barData?.dataSets val valueOffsetPlus = 5f.convertDpToPixel() var posOffset: Float var negOffset: Float val drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled - for (i in 0.. + for (i in 0..= 0) posOffset else negOffset), - y + halfTextHeight, - dataSet.getValueTextColor(j / 2) - ) + if (!viewPortHandler.isInBoundsX(buffer.buffer[j])) { + j += 4 + continue } - if (barEntry.icon != null && dataSet.isDrawIcons) { - val icon = barEntry.icon - - var px = buffer.buffer[j + 2] + (if (valueY >= 0) posOffset else negOffset) - var py = y - - px += iconsOffset.x - py += iconsOffset.y - - icon?.let { - Utils.drawImage( - canvas, - it, - px.toInt(), - py.toInt() - ) - } + if (!viewPortHandler.isInBoundsBottom(buffer.buffer[j + 1])) { + j += 4 + continue } - } - j += 4 - } - - // if each value of a potential stack should be drawn - } else { - val trans = dataProvider.getTransformer(dataSet.axisDependency) - - var bufferIndex = 0 - var index = 0 - - while (index < dataSet.entryCount * animator.phaseX) { - val barEntry = dataSet.getEntryForIndex(index) - barEntry?.let { - val color = dataSet.getValueTextColor(index) - val vals = it.yVals - - // we still draw stacked bars, but there is one - // non-stacked - // in between - if (vals == null) { - if (!viewPortHandler.isInBoundsTop(buffer.buffer[bufferIndex + 1])) { - break - } - - if (!viewPortHandler.isInBoundsX(buffer.buffer[bufferIndex])) { - continue - } - - if (!viewPortHandler.isInBoundsBottom(buffer.buffer[bufferIndex + 1])) { - continue - } - - val formattedValue = formatter.getFormattedValue( - it.y, - it, i, viewPortHandler - ) + val barEntry = dataSet.getEntryForIndex(j / 4) + barEntry?.let { + val valueY = barEntry.y + val formattedValue = formatter.getFormattedValue(valueY, barEntry, i, viewPortHandler) // calculate the correct offset depending on the draw position of the value val valueTextWidth = Utils.calcTextWidth(paintValues, formattedValue).toFloat() posOffset = (if (drawValueAboveBar) valueOffsetPlus else -(valueTextWidth + valueOffsetPlus)) - negOffset = (if (drawValueAboveBar) -(valueTextWidth + valueOffsetPlus) else valueOffsetPlus) + negOffset = ((if (drawValueAboveBar) -(valueTextWidth + valueOffsetPlus) else valueOffsetPlus) + - (buffer.buffer[j + 2] - buffer.buffer[j])) if (isInverted) { posOffset = -posOffset - valueTextWidth @@ -315,69 +242,67 @@ open class HorizontalBarChartRenderer( if (dataSet.isDrawValues) { drawValue( - canvas, formattedValue!!, - buffer.buffer[bufferIndex + 2] - + (if (it.y >= 0) posOffset else negOffset), - buffer.buffer[bufferIndex + 1] + halfTextHeight, color + canvas, + formattedValue!!, + buffer.buffer[j + 2] + (if (valueY >= 0) posOffset else negOffset), + y + halfTextHeight, + dataSet.getValueTextColor(j / 2) ) } - if (it.icon != null && dataSet.isDrawIcons) { - val icon = it.icon + if (barEntry.icon != null && dataSet.isDrawIcons) { + val icon = barEntry.icon - var px = (buffer.buffer[bufferIndex + 2] - + (if (it.y >= 0) posOffset else negOffset)) - var py = buffer.buffer[bufferIndex + 1] + var px = buffer.buffer[j + 2] + (if (valueY >= 0) posOffset else negOffset) + var py = y px += iconsOffset.x py += iconsOffset.y - icon?.let { myIcon -> + icon?.let { Utils.drawImage( canvas, - myIcon, + it, px.toInt(), py.toInt() ) } } - } else { - val transformed = FloatArray(vals.size * 2) + } + j += 4 + } - var posY = 0f - var negY = -it.negativeSum + // if each value of a potential stack should be drawn + } else { + val trans = dataProvider.getTransformer(dataSet.axisDependency) - run { - var k = 0 - var idx = 0 - while (k < transformed.size) { - val value = vals[idx] - val y: Float - - if (value == 0.0f && (posY == 0.0f || negY == 0.0f)) { - // Take care of the situation of a 0.0 value, which overlaps a non-zero bar - y = value - } else if (value >= 0.0f) { - posY += value - y = posY - } else { - y = negY - negY -= value - } + var bufferIndex = 0 + var index = 0 - transformed[k] = y * phaseY - k += 2 - idx++ + while (index < dataSet.entryCount * animator.phaseX) { + val barEntry = dataSet.getEntryForIndex(index) + barEntry?.let { + val color = dataSet.getValueTextColor(index) + val vals = it.yVals + + // we still draw stacked bars, but there is one + // non-stacked + // in between + if (vals == null) { + if (!viewPortHandler.isInBoundsTop(buffer.buffer[bufferIndex + 1])) { + break } - } - trans!!.pointValuesToPixel(transformed) + if (!viewPortHandler.isInBoundsX(buffer.buffer[bufferIndex])) { + continue + } + + if (!viewPortHandler.isInBoundsBottom(buffer.buffer[bufferIndex + 1])) { + continue + } - var k = 0 - while (k < transformed.size) { - val valueY = vals[k / 2] val formattedValue = formatter.getFormattedValue( - valueY, + it.y, it, i, viewPortHandler ) @@ -391,52 +316,131 @@ open class HorizontalBarChartRenderer( negOffset = -negOffset - valueTextWidth } - val drawBelow = (valueY == 0.0f && negY == 0.0f && posY > 0.0f) || valueY < 0.0f - - val x = (transformed[k] + (if (drawBelow) negOffset else posOffset)) - val y = (buffer.buffer[bufferIndex + 1] + buffer.buffer[bufferIndex + 3]) / 2f - - if (!viewPortHandler.isInBoundsTop(y)) { - break - } - - if (!viewPortHandler.isInBoundsX(x)) { - k += 2 - continue - } - - if (!viewPortHandler.isInBoundsBottom(y)) { - k += 2 - continue - } - if (dataSet.isDrawValues) { - drawValue(canvas, formattedValue!!, x, y + halfTextHeight, color) + drawValue( + canvas, formattedValue!!, + buffer.buffer[bufferIndex + 2] + + (if (it.y >= 0) posOffset else negOffset), + buffer.buffer[bufferIndex + 1] + halfTextHeight, color + ) } if (it.icon != null && dataSet.isDrawIcons) { val icon = it.icon + var px = (buffer.buffer[bufferIndex + 2] + + (if (it.y >= 0) posOffset else negOffset)) + var py = buffer.buffer[bufferIndex + 1] + + px += iconsOffset.x + py += iconsOffset.y + icon?.let { myIcon -> Utils.drawImage( canvas, myIcon, - (x + iconsOffset.x).toInt(), - (y + iconsOffset.y).toInt() + px.toInt(), + py.toInt() ) } } - k += 2 + } else { + val transformed = FloatArray(vals.size * 2) + + var posY = 0f + var negY = -it.negativeSum + + run { + var k = 0 + var idx = 0 + while (k < transformed.size) { + val value = vals[idx] + val y: Float + + if (value == 0.0f && (posY == 0.0f || negY == 0.0f)) { + // Take care of the situation of a 0.0 value, which overlaps a non-zero bar + y = value + } else if (value >= 0.0f) { + posY += value + y = posY + } else { + y = negY + negY -= value + } + + transformed[k] = y * phaseY + k += 2 + idx++ + } + } + + trans!!.pointValuesToPixel(transformed) + + var k = 0 + while (k < transformed.size) { + val valueY = vals[k / 2] + val formattedValue = formatter.getFormattedValue( + valueY, + it, i, viewPortHandler + ) + + // calculate the correct offset depending on the draw position of the value + val valueTextWidth = Utils.calcTextWidth(paintValues, formattedValue).toFloat() + posOffset = (if (drawValueAboveBar) valueOffsetPlus else -(valueTextWidth + valueOffsetPlus)) + negOffset = (if (drawValueAboveBar) -(valueTextWidth + valueOffsetPlus) else valueOffsetPlus) + + if (isInverted) { + posOffset = -posOffset - valueTextWidth + negOffset = -negOffset - valueTextWidth + } + + val drawBelow = (valueY == 0.0f && negY == 0.0f && posY > 0.0f) || valueY < 0.0f + + val x = (transformed[k] + (if (drawBelow) negOffset else posOffset)) + val y = (buffer.buffer[bufferIndex + 1] + buffer.buffer[bufferIndex + 3]) / 2f + + if (!viewPortHandler.isInBoundsTop(y)) { + break + } + + if (!viewPortHandler.isInBoundsX(x)) { + k += 2 + continue + } + + if (!viewPortHandler.isInBoundsBottom(y)) { + k += 2 + continue + } + + if (dataSet.isDrawValues) { + drawValue(canvas, formattedValue!!, x, y + halfTextHeight, color) + } + + if (it.icon != null && dataSet.isDrawIcons) { + val icon = it.icon + + icon?.let { myIcon -> + Utils.drawImage( + canvas, + myIcon, + (x + iconsOffset.x).toInt(), + (y + iconsOffset.y).toInt() + ) + } + } + k += 2 + } } - } - bufferIndex = if (vals == null) bufferIndex + 4 else bufferIndex + 4 * vals.size + bufferIndex = if (vals == null) bufferIndex + 4 else bufferIndex + 4 * vals.size + } + index++ } - index++ } - } - MPPointF.recycleInstance(iconsOffset) + MPPointF.recycleInstance(iconsOffset) + } } } } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedBarChartRenderer.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedBarChartRenderer.kt index 6bd3880dc..e07c201dd 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedBarChartRenderer.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedBarChartRenderer.kt @@ -45,119 +45,135 @@ class RoundedBarChartRenderer(chart: BarDataProvider, animator: ChartAnimator, v if (dataProvider.isDrawBarShadowEnabled) { shadowPaint.color = dataSet.barShadowColor - val barData = dataProvider.barData - val barWidth = barData.barWidth - val barWidthHalf = barWidth / 2.0f - var x: Float - var i = 0 - val count = min((dataSet.entryCount.toFloat() * phaseX).toDouble().toInt().toDouble(), dataSet.entryCount.toDouble()) - while (i < count) { - dataSet.getEntryForIndex(i)?.let { barEntry -> - x = barEntry.x - mBarShadowRectBuffer.left = x - barWidthHalf - mBarShadowRectBuffer.right = x + barWidthHalf - } - trans!!.rectValueToPixel(mBarShadowRectBuffer) - if (!viewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right)) { - i++ - continue - } - if (!viewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left)) { - break - } - mBarShadowRectBuffer.top = viewPortHandler.contentTop() - mBarShadowRectBuffer.bottom = viewPortHandler.contentBottom() + dataProvider.barData?.let { barData -> + val barWidth = barData.barWidth + val barWidthHalf = barWidth / 2.0f + var x: Float + var i = 0 + val count = min((dataSet.entryCount.toFloat() * phaseX).toDouble().toInt().toDouble(), dataSet.entryCount.toDouble()) + while (i < count) { + dataSet.getEntryForIndex(i)?.let { barEntry -> + x = barEntry.x + mBarShadowRectBuffer.left = x - barWidthHalf + mBarShadowRectBuffer.right = x + barWidthHalf + } + trans!!.rectValueToPixel(mBarShadowRectBuffer) + if (!viewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right)) { + i++ + continue + } + if (!viewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left)) { + break + } + mBarShadowRectBuffer.top = viewPortHandler.contentTop() + mBarShadowRectBuffer.bottom = viewPortHandler.contentBottom() - if (roundedShadowRadius > 0) { - canvas.drawRoundRect(barRect, roundedShadowRadius, roundedShadowRadius, shadowPaint) - } else { - canvas.drawRect(mBarShadowRectBuffer, shadowPaint) + if (roundedShadowRadius > 0) { + canvas.drawRoundRect(barRect, roundedShadowRadius, roundedShadowRadius, shadowPaint) + } else { + canvas.drawRect(mBarShadowRectBuffer, shadowPaint) + } + i++ } - i++ + } - } - val buffer = barBuffers[index]!! - buffer.setPhases(phaseX, phaseY) - buffer.setDataSet(index) - buffer.setInverted(dataProvider.isInverted(dataSet.axisDependency)) - buffer.setBarWidth(dataProvider.barData.barWidth) - buffer.feed(dataSet) - trans!!.pointValuesToPixel(buffer.buffer) - - // if multiple colors has been assigned to Bar Chart - dataSet.colors.let { - if (it.size > 1) { - var j = 0 - while (j < buffer.size()) { - if (!viewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) { - j += 4 - continue - } + val buffer = barBuffers[index]!! + buffer.setPhases(phaseX, phaseY) + buffer.setDataSet(index) + buffer.setInverted(dataProvider.isInverted(dataSet.axisDependency)) + dataProvider.barData?.let { buffer.setBarWidth(it.barWidth) } + buffer.feed(dataSet) + trans!!.pointValuesToPixel(buffer.buffer) + + // if multiple colors has been assigned to Bar Chart + dataSet.colors.let { + if (it.size > 1) { + var j = 0 + while (j < buffer.size()) { + if (!viewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) { + j += 4 + continue + } - if (!viewPortHandler.isInBoundsRight(buffer.buffer[j])) { - break - } + if (!viewPortHandler.isInBoundsRight(buffer.buffer[j])) { + break + } - if (dataProvider.isDrawBarShadowEnabled) { - if (roundedShadowRadius > 0) { - canvas.drawRoundRect( - RectF( + if (dataProvider.isDrawBarShadowEnabled) { + if (roundedShadowRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], viewPortHandler.contentTop(), + buffer.buffer[j + 2], + viewPortHandler.contentBottom() + ), roundedShadowRadius, roundedShadowRadius, shadowPaint + ) + } else { + canvas.drawRect( buffer.buffer[j], viewPortHandler.contentTop(), buffer.buffer[j + 2], - viewPortHandler.contentBottom() - ), roundedShadowRadius, roundedShadowRadius, shadowPaint + viewPortHandler.contentBottom(), shadowPaint + ) + } + } + + // Set the color for the currently drawn value. If the index + paintRender.color = dataSet.getColorByIndex(j / 4) + + if (roundedPositiveDataSetRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender ) } else { canvas.drawRect( - buffer.buffer[j], viewPortHandler.contentTop(), - buffer.buffer[j + 2], - viewPortHandler.contentBottom(), shadowPaint + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3], paintRender ) } + j += 4 } + } else { + paintRender.color = dataSet.color - // Set the color for the currently drawn value. If the index - paintRender.color = dataSet.getColorByIndex(j / 4) - - if (roundedPositiveDataSetRadius > 0) { - canvas.drawRoundRect( - RectF( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender - ) - } else { - canvas.drawRect( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3], paintRender - ) - } - j += 4 - } - } else { - paintRender.color = dataSet.color + var j = 0 + while (j < buffer.size()) { + if (!viewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) { + j += 4 + continue + } - var j = 0 - while (j < buffer.size()) { - if (!viewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) { - j += 4 - continue - } + if (!viewPortHandler.isInBoundsRight(buffer.buffer[j])) { + break + } - if (!viewPortHandler.isInBoundsRight(buffer.buffer[j])) { - break - } + if (dataProvider.isDrawBarShadowEnabled) { + if (roundedShadowRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], viewPortHandler.contentTop(), + buffer.buffer[j + 2], + viewPortHandler.contentBottom() + ), roundedShadowRadius, roundedShadowRadius, shadowPaint + ) + } else { + canvas.drawRect( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3], paintRender + ) + } + } - if (dataProvider.isDrawBarShadowEnabled) { - if (roundedShadowRadius > 0) { + if (roundedPositiveDataSetRadius > 0) { canvas.drawRoundRect( RectF( - buffer.buffer[j], viewPortHandler.contentTop(), - buffer.buffer[j + 2], - viewPortHandler.contentBottom() - ), roundedShadowRadius, roundedShadowRadius, shadowPaint + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender ) } else { canvas.drawRect( @@ -165,149 +181,135 @@ class RoundedBarChartRenderer(chart: BarDataProvider, animator: ChartAnimator, v buffer.buffer[j + 3], paintRender ) } + j += 4 } + } + } - if (roundedPositiveDataSetRadius > 0) { - canvas.drawRoundRect( + val isSingleColor = dataSet.colors.size == 1 + if (isSingleColor) { + paintRender.color = dataSet.getColorByIndex(index) + } + + var j = 0 + while (j < buffer.size()) { + if (!viewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) { + j += 4 + continue + } + + if (!viewPortHandler.isInBoundsRight(buffer.buffer[j])) { + break + } + + if (!isSingleColor) { + paintRender.color = dataSet.getColorByIndex(j / 4) + } + + paintRender.shader = LinearGradient( + buffer.buffer[j], + buffer.buffer[j + 3], + buffer.buffer[j], + buffer.buffer[j + 1], + dataSet.getColorByIndex(j / 4), + dataSet.getColorByIndex(j / 4), + Shader.TileMode.MIRROR + ) + + paintRender.shader = LinearGradient( + buffer.buffer[j], + buffer.buffer[j + 3], + buffer.buffer[j], + buffer.buffer[j + 1], + dataSet.getColorByIndex(j / 4), + dataSet.getColorByIndex(j / 4), + Shader.TileMode.MIRROR + ) + + dataSet.getEntryForIndex(j / 4)?.let { barEntry -> + + if ((barEntry.y < 0 && roundedNegativeDataSetRadius > 0)) { + val path2 = roundRect( RectF( buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], buffer.buffer[j + 3] - ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender + ), roundedNegativeDataSetRadius, roundedNegativeDataSetRadius, tl = true, tr = true, br = true, bl = true ) + canvas.drawPath(path2, paintRender) + } else if ((barEntry.y > 0 && roundedPositiveDataSetRadius > 0)) { + val path2 = roundRect( + RectF( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, tl = true, tr = true, br = true, bl = true + ) + canvas.drawPath(path2, paintRender) } else { canvas.drawRect( buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], buffer.buffer[j + 3], paintRender ) } - j += 4 } - } - } - - - val isSingleColor = dataSet.colors.size == 1 - if (isSingleColor) { - paintRender.color = dataSet.getColorByIndex(index) - } - - var j = 0 - while (j < buffer.size()) { - if (!viewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) { j += 4 - continue - } - - if (!viewPortHandler.isInBoundsRight(buffer.buffer[j])) { - break - } - - if (!isSingleColor) { - paintRender.color = dataSet.getColorByIndex(j / 4) } - - paintRender.shader = LinearGradient( - buffer.buffer[j], - buffer.buffer[j + 3], - buffer.buffer[j], - buffer.buffer[j + 1], - dataSet.getColorByIndex(j / 4), - dataSet.getColorByIndex(j / 4), - Shader.TileMode.MIRROR - ) - - paintRender.shader = LinearGradient( - buffer.buffer[j], - buffer.buffer[j + 3], - buffer.buffer[j], - buffer.buffer[j + 1], - dataSet.getColorByIndex(j / 4), - dataSet.getColorByIndex(j / 4), - Shader.TileMode.MIRROR - ) - - dataSet.getEntryForIndex(j / 4)?.let { barEntry -> - - if ((barEntry.y < 0 && roundedNegativeDataSetRadius > 0)) { - val path2 = roundRect( - RectF( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedNegativeDataSetRadius, roundedNegativeDataSetRadius, tl = true, tr = true, br = true, bl = true - ) - canvas.drawPath(path2, paintRender) - } else if ((barEntry.y > 0 && roundedPositiveDataSetRadius > 0)) { - val path2 = roundRect( - RectF( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, tl = true, tr = true, br = true, bl = true - ) - canvas.drawPath(path2, paintRender) - } else { - canvas.drawRect( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3], paintRender - ) - } - } - j += 4 } } override fun drawHighlighted(canvas: Canvas, indices: Array) { - val barData = dataProvider.barData - - for (high in indices) { - val set = barData.getDataSetByIndex(high.dataSetIndex) - - if (set == null || !set.isHighlightEnabled) { - continue - } + dataProvider.barData?.let { barData -> - set.getEntryForXValue(high.x, high.y)?.let { barEntry -> + for (high in indices) { + val set = barData.getDataSetByIndex(high.dataSetIndex) - if (!isInBoundsX(barEntry, set)) { + if (set == null || !set.isHighlightEnabled) { continue } - val trans = dataProvider.getTransformer(set.axisDependency) + set.getEntryForXValue(high.x, high.y)?.let { barEntry -> - paintHighlight.color = set.highLightColor - paintHighlight.alpha = set.highLightAlpha + if (!isInBoundsX(barEntry, set)) { + continue + } - val isStack = high.stackIndex >= 0 && barEntry.isStacked + val trans = dataProvider.getTransformer(set.axisDependency) - val y1: Float - val y2: Float + paintHighlight.color = set.highLightColor + paintHighlight.alpha = set.highLightAlpha - if (isStack) { - if (dataProvider.isHighlightFullBarEnabled) { - y1 = barEntry.positiveSum - y2 = -barEntry.negativeSum - } else { - val range = barEntry.ranges[high.stackIndex] + val isStack = high.stackIndex >= 0 && barEntry.isStacked + + val y1: Float + val y2: Float - y1 = range.from - y2 = range.to + if (isStack) { + if (dataProvider.isHighlightFullBarEnabled) { + y1 = barEntry.positiveSum + y2 = -barEntry.negativeSum + } else { + val range = barEntry.ranges[high.stackIndex] + + y1 = range.from + y2 = range.to + } + } else { + y1 = barEntry.y + y2 = 0f } - } else { - y1 = barEntry.y - y2 = 0f - } - prepareBarHighlight(barEntry.x, y1, y2, barData.barWidth / 2f, trans!!) + prepareBarHighlight(barEntry.x, y1, y2, barData.barWidth / 2f, trans!!) - setHighlightDrawPos(high, barRect) + setHighlightDrawPos(high, barRect) - val path2 = roundRect( - RectF( - barRect.left, barRect.top, barRect.right, - barRect.bottom - ), mRadius, mRadius, tl = true, tr = true, br = true, bl = true - ) + val path2 = roundRect( + RectF( + barRect.left, barRect.top, barRect.right, + barRect.bottom + ), mRadius, mRadius, tl = true, tr = true, br = true, bl = true + ) - canvas.drawPath(path2, paintHighlight) + canvas.drawPath(path2, paintHighlight) + } } } } diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedHorizontalBarChartRenderer.kt b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedHorizontalBarChartRenderer.kt index 42b49fb1f..e47087ebc 100644 --- a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedHorizontalBarChartRenderer.kt +++ b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/RoundedHorizontalBarChartRenderer.kt @@ -36,97 +36,148 @@ class RoundedHorizontalBarChartRenderer(chart: BarDataProvider, animator: ChartA if (dataProvider.isDrawBarShadowEnabled) { shadowPaint.color = dataSet.barShadowColor - val barData = dataProvider.barData - val barWidth = barData.barWidth - val barWidthHalf = barWidth / 2.0f - var x: Float - var i = 0 - val count = min((dataSet.entryCount.toFloat() * phaseX).toDouble().toInt().toDouble(), dataSet.entryCount.toDouble()) - while (i < count) { - dataSet.getEntryForIndex(i)?.let { barEntry -> - x = barEntry.x - mBarShadowRectBuffer.top = x - barWidthHalf - mBarShadowRectBuffer.bottom = x + barWidthHalf - } - trans!!.rectValueToPixel(mBarShadowRectBuffer) - if (!viewPortHandler.isInBoundsTop(mBarShadowRectBuffer.bottom)) { - i++ - continue - } - if (!viewPortHandler.isInBoundsBottom(mBarShadowRectBuffer.top)) { - break - } - mBarShadowRectBuffer.left = viewPortHandler.contentLeft() - mBarShadowRectBuffer.right = viewPortHandler.contentRight() + dataProvider.barData?.let { barData -> + val barWidth = barData.barWidth + val barWidthHalf = barWidth / 2.0f + var x: Float + var i = 0 + val count = min((dataSet.entryCount.toFloat() * phaseX).toDouble().toInt().toDouble(), dataSet.entryCount.toDouble()) + while (i < count) { + dataSet.getEntryForIndex(i)?.let { barEntry -> + x = barEntry.x + mBarShadowRectBuffer.top = x - barWidthHalf + mBarShadowRectBuffer.bottom = x + barWidthHalf + } + trans!!.rectValueToPixel(mBarShadowRectBuffer) + if (!viewPortHandler.isInBoundsTop(mBarShadowRectBuffer.bottom)) { + i++ + continue + } + if (!viewPortHandler.isInBoundsBottom(mBarShadowRectBuffer.top)) { + break + } + mBarShadowRectBuffer.left = viewPortHandler.contentLeft() + mBarShadowRectBuffer.right = viewPortHandler.contentRight() - if (roundedShadowRadius > 0) { - canvas.drawRoundRect(barRect, roundedShadowRadius, roundedShadowRadius, shadowPaint) - } else { - canvas.drawRect(mBarShadowRectBuffer, shadowPaint) + if (roundedShadowRadius > 0) { + canvas.drawRoundRect(barRect, roundedShadowRadius, roundedShadowRadius, shadowPaint) + } else { + canvas.drawRect(mBarShadowRectBuffer, shadowPaint) + } + i++ } - i++ } - } - val buffer = barBuffers[index]!! - buffer.setPhases(phaseX, phaseY) - buffer.setDataSet(index) - buffer.setInverted(dataProvider.isInverted(dataSet.axisDependency)) - buffer.setBarWidth(dataProvider.barData.barWidth) - buffer.feed(dataSet) - trans!!.pointValuesToPixel(buffer.buffer) + val buffer = barBuffers[index]!! + buffer.setPhases(phaseX, phaseY) + buffer.setDataSet(index) + buffer.setInverted(dataProvider.isInverted(dataSet.axisDependency)) + dataProvider.barData?.let { buffer.setBarWidth(it.barWidth) } + buffer.feed(dataSet) + trans!!.pointValuesToPixel(buffer.buffer) - // if multiple colors has been assigned to Bar Chart - if (dataSet.colors.size > 1) { - var j = 0 - while (j < buffer.size()) { - if (!viewPortHandler.isInBoundsTop(buffer.buffer[j + 3])) { - j += 4 - continue - } + // if multiple colors has been assigned to Bar Chart + if (dataSet.colors.size > 1) { + var j = 0 + while (j < buffer.size()) { + if (!viewPortHandler.isInBoundsTop(buffer.buffer[j + 3])) { + j += 4 + continue + } - if (!viewPortHandler.isInBoundsBottom(buffer.buffer[j + 1])) { - break - } + if (!viewPortHandler.isInBoundsBottom(buffer.buffer[j + 1])) { + break + } - if (dataProvider.isDrawBarShadowEnabled) { - if (roundedShadowRadius > 0) { - canvas.drawRoundRect( - RectF( + if (dataProvider.isDrawBarShadowEnabled) { + if (roundedShadowRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], viewPortHandler.contentTop(), + buffer.buffer[j + 2], + viewPortHandler.contentBottom() + ), roundedShadowRadius, roundedShadowRadius, shadowPaint + ) + } else { + canvas.drawRect( buffer.buffer[j], viewPortHandler.contentTop(), buffer.buffer[j + 2], - viewPortHandler.contentBottom() - ), roundedShadowRadius, roundedShadowRadius, shadowPaint + viewPortHandler.contentBottom(), shadowPaint + ) + } + } + + // Set the color for the currently drawn value. If the index + paintRender.color = dataSet.getColorByIndex(j / 4) + + if (roundedPositiveDataSetRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender ) } else { canvas.drawRect( - buffer.buffer[j], viewPortHandler.contentTop(), - buffer.buffer[j + 2], - viewPortHandler.contentBottom(), shadowPaint + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3], paintRender ) } + j += 4 } + } else { + paintRender.color = dataSet.color - // Set the color for the currently drawn value. If the index - paintRender.color = dataSet.getColorByIndex(j / 4) + var j = 0 + while (j < buffer.size()) { + if (!viewPortHandler.isInBoundsTop(buffer.buffer[j + 3])) { + j += 4 + continue + } + + if (!viewPortHandler.isInBoundsBottom(buffer.buffer[j + 1])) { + break + } + + if (dataProvider.isDrawBarShadowEnabled) { + if (roundedShadowRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], viewPortHandler.contentTop(), + buffer.buffer[j + 2], + viewPortHandler.contentBottom() + ), roundedShadowRadius, roundedShadowRadius, shadowPaint + ) + } else { + canvas.drawRect( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3], paintRender + ) + } + } - if (roundedPositiveDataSetRadius > 0) { - canvas.drawRoundRect( - RectF( + if (roundedPositiveDataSetRadius > 0) { + canvas.drawRoundRect( + RectF( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender + ) + } else { + canvas.drawRect( buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender - ) - } else { - canvas.drawRect( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3], paintRender - ) + buffer.buffer[j + 3], paintRender + ) + } + j += 4 } - j += 4 + + } + + val isSingleColor = dataSet.colors.size == 1 + if (isSingleColor) { + paintRender.color = dataSet.getColorByIndex(index) } - } else { - paintRender.color = dataSet.color var j = 0 while (j < buffer.size()) { @@ -139,15 +190,27 @@ class RoundedHorizontalBarChartRenderer(chart: BarDataProvider, animator: ChartA break } - if (dataProvider.isDrawBarShadowEnabled) { - if (roundedShadowRadius > 0) { - canvas.drawRoundRect( + if (!isSingleColor) { + paintRender.color = dataSet.getColorByIndex(j / 4) + } + + dataSet.getEntryForIndex(j / 4)?.let { barEntry -> + if ((barEntry.y < 0 && roundedNegativeDataSetRadius > 0)) { + val path2 = roundRect( RectF( - buffer.buffer[j], viewPortHandler.contentTop(), - buffer.buffer[j + 2], - viewPortHandler.contentBottom() - ), roundedShadowRadius, roundedShadowRadius, shadowPaint + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedNegativeDataSetRadius, roundedNegativeDataSetRadius, true, true, true, true ) + canvas.drawPath(path2, paintRender) + } else if ((barEntry.y > 0 && roundedPositiveDataSetRadius > 0)) { + val path2 = roundRect( + RectF( + buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], + buffer.buffer[j + 3] + ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, true, true, true, true + ) + canvas.drawPath(path2, paintRender) } else { canvas.drawRect( buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], @@ -155,69 +218,8 @@ class RoundedHorizontalBarChartRenderer(chart: BarDataProvider, animator: ChartA ) } } - - if (roundedPositiveDataSetRadius > 0) { - canvas.drawRoundRect( - RectF( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, paintRender - ) - } else { - canvas.drawRect( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3], paintRender - ) - } - j += 4 - } - } - - val isSingleColor = dataSet.colors.size == 1 - if (isSingleColor) { - paintRender.color = dataSet.getColorByIndex(index) - } - - var j = 0 - while (j < buffer.size()) { - if (!viewPortHandler.isInBoundsTop(buffer.buffer[j + 3])) { j += 4 - continue - } - - if (!viewPortHandler.isInBoundsBottom(buffer.buffer[j + 1])) { - break - } - - if (!isSingleColor) { - paintRender.color = dataSet.getColorByIndex(j / 4) - } - - dataSet.getEntryForIndex(j / 4)?.let { barEntry -> - if ((barEntry.y < 0 && roundedNegativeDataSetRadius > 0)) { - val path2 = roundRect( - RectF( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedNegativeDataSetRadius, roundedNegativeDataSetRadius, true, true, true, true - ) - canvas.drawPath(path2, paintRender) - } else if ((barEntry.y > 0 && roundedPositiveDataSetRadius > 0)) { - val path2 = roundRect( - RectF( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3] - ), roundedPositiveDataSetRadius, roundedPositiveDataSetRadius, true, true, true, true - ) - canvas.drawPath(path2, paintRender) - } else { - canvas.drawRect( - buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], - buffer.buffer[j + 3], paintRender - ) - } } - j += 4 } } diff --git a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt index 2b9051579..b056fbc36 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/BarChartActivityMultiDataset.kt @@ -159,13 +159,13 @@ class BarChartActivityMultiDataset : DemoBase(), OnSeekBarChangeListener, OnChar } // specify the width each bar should have - binding.chart1.barData.barWidth = barWidth + binding.chart1.barData?.let { it.barWidth = barWidth } // restrict the x-axis range binding.chart1.xAxis.axisMinimum = startYear.toFloat() // barData.getGroupWith(...) is a helper that calculates the width each group needs based on the provided parameters - binding.chart1.xAxis.axisMaximum = startYear + binding.chart1.barData.getGroupWidth(groupSpace, barSpace) * groupCount + binding.chart1.barData?.let { binding.chart1.xAxis.axisMaximum = startYear + it.getGroupWidth(groupSpace, barSpace) * groupCount } binding.chart1.groupBars(startYear.toFloat(), groupSpace, barSpace) binding.chart1.invalidate() } diff --git a/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt index 08045d77c..3f28bff1f 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/StackedBarActivity.kt @@ -110,8 +110,7 @@ class StackedBarActivity : DemoBase(), OnSeekBarChangeListener, OnChartValueSele val set1: BarDataSet if (binding.chart1.data != null && - binding.chart1.data!!.dataSetCount > 0 - ) { + binding.chart1.data!!.dataSetCount > 0) { set1 = binding.chart1.data!!.getDataSetByIndex(0) as BarDataSet set1.entries = values binding.chart1.data!!.notifyDataChanged()