How to draw 4 sides border around a bar in MPAndroidChart BarCart?

52 Views Asked by At

I am new to Android and am using MPAndroidChart to draw a bar chart. How can I draw a four-sided border around each bar in the graph that is displayed?

Show bars like this image.

image

and also bars should not be attached from the bottom; they should be drawn the same as in this picture, and they should shadow when clicked on the bars as in this attachment.

Thanks

I tried this, but it only adds the two top left and top right borders, and the bars are also attached to the bottom on the x-axis.

override fun drawDataSet(c: Canvas, dataSet: IBarDataSet, index: Int) {
    val trans: Transformer = mChart.getTransformer(dataSet.axisDependency)
    mShadowPaint.color = dataSet.barShadowColor
    val phaseX = mAnimator.phaseX
    val phaseY = mAnimator.phaseY
    if (mBarBuffers != null) {
        // initialize the buffer
        val buffer = mBarBuffers[index]
        buffer.setPhases(phaseX, phaseY)
        buffer.setDataSet(index)
        buffer.setBarWidth(mChart.barData.barWidth)
        buffer.setInverted(mChart.isInverted(dataSet.axisDependency))
        buffer.feed(dataSet)
        trans.pointValuesToPixel(buffer.buffer)

        // if multiple colors
        if (dataSet.colors.size > 1) {
            var j = 0
            while (j < buffer.size()) {
                if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) {
                    j += 4
                    continue
                }
                if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j])) break
                if (mChart.isDrawBarShadowEnabled) {
                    if (mRadius > 0) c.drawRoundRect(
                        RectF(
                            buffer.buffer[j], mViewPortHandler.contentTop(),
                            buffer.buffer[j + 2], mViewPortHandler.contentBottom()
                        ), mRadius, mRadius, mShadowPaint
                    ) else c.drawRect(
                        buffer.buffer[j], mViewPortHandler.contentTop(),
                        buffer.buffer[j + 2], mViewPortHandler.contentBottom(), mShadowPaint
                    )
                }

                // Set the color for the currently drawn value. If the index
                // is
                // out of bounds, reuse colors.
                mRenderPaint.color = dataSet.getColor(j / 4)
                if (mRadius > 0) {
                    val path: Path = RoundedRect(
                        buffer.buffer[j],
                        buffer.buffer[j + 1],
                        buffer.buffer[j + 2],
                        buffer.buffer[j + 3], 15f, 15f, true, true, false, false
                    )
                    c.drawPath(path, mRenderPaint)
                } else c.drawRect(
                    buffer.buffer[j],
                    buffer.buffer[j + 1],
                    buffer.buffer[j + 2], buffer.buffer[j + 3], mRenderPaint
                )
                j += 4
            }
        } else {
            mRenderPaint.color = dataSet.color
            var j = 0
            while (j < buffer.size()) {
                if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) {
                    j += 4
                    continue
                }
                if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j])) break
                if (mChart.isDrawBarShadowEnabled) {
                    if (mRadius > 0) c.drawRoundRect(
                        RectF(
                            buffer.buffer[j], mViewPortHandler.contentTop(),
                            buffer.buffer[j + 2],
                            mViewPortHandler.contentBottom()
                        ), mRadius, mRadius, mShadowPaint
                    ) else c.drawRect(
                        buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3], mRenderPaint
                    )
                }
                if (mRadius > 0) {
                    val path: Path = RoundedRect(
                        buffer.buffer[j],
                        buffer.buffer[j + 1],
                        buffer.buffer[j + 2],
                        buffer.buffer[j + 3], 25f, 25f, true, true, false, false
                    )
                    c.drawPath(path, mRenderPaint)
                } else c.drawRect(
                    buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                    buffer.buffer[j + 3], mRenderPaint
                )
                j += 4
            }
        }
    }
}

companion object {
    fun RoundedRect(
        left: Float, top: Float, right: Float, bottom: Float, rx: Float, ry: Float,
        tl: Boolean, tr: Boolean, br: Boolean, bl: Boolean
    ): Path {
        var rx = rx
        var ry = ry
        val path = Path()
        if (rx < 0) rx = 0f
        if (ry < 0) ry = 0f
        val width = right - left
        val height = bottom - top
        if (rx > width / 2) rx = width / 2
        if (ry > height / 2) ry = height / 2
        val widthMinusCorners = width - 2 * rx
        val heightMinusCorners = height - 2 * ry

        path.moveTo(right, top + ry)
        if (tr) path.rQuadTo(0f, -ry, -rx, -ry) //top-right corner
        else {
            path.rLineTo(0f, -ry)
            path.rLineTo(-rx, 0f)
        }
        path.rLineTo(-widthMinusCorners, 0f)
        if (tl) path.rQuadTo(-rx, 0f, -rx, ry) //top-left corner
        else {
            path.rLineTo(-rx, 0f)
            path.rLineTo(0f, ry)
        }
        path.rLineTo(0f, heightMinusCorners)
        if (bl) path.rQuadTo(0f, ry, rx, ry) //bottom-left corner
        else {
            path.rLineTo(0f, ry)
            path.rLineTo(rx, 0f)
        }
        path.rLineTo(widthMinusCorners, 0f)
        if (br) path.rQuadTo(rx, 0f, rx, -ry) //bottom-right corner
        else {
            path.rLineTo(rx, 0f)
            path.rLineTo(0f, -ry)
        }
        path.rLineTo(0f, -heightMinusCorners)
        path.close() //Given close, last line to can be removed.
        return path
    }
}
1

There are 1 best solutions below

2
Laxmi kant On

You can draw a rounded border around the bars in a bar chart using the library. You've defined a custom function RoundedRect that creates a rounded rectangle path, and you're using it to draw the bars. To draw a four-sided border around the bars, you can modify your drawDataSet

method as follows:

    override fun drawDataSet(c: Canvas, dataSet: IBarDataSet, index: Int) {
        val trans: Transformer = mChart.getTransformer(dataSet.axisDependency)
        mShadowPaint.color = dataSet.barShadowColor
        val phaseX = mAnimator.phaseX
        val phaseY = mAnimator.phaseY

        if (mBarBuffers != null) {
            val buffer = mBarBuffers[index]
            buffer.setPhases(phaseX, phaseY)
            buffer.setDataSet(index)
            buffer.setBarWidth(mChart.barData.barWidth)
            buffer.setInverted(mChart.isInverted(dataSet.axisDependency))
            buffer.feed(dataSet)
            trans.pointValuesToPixel(buffer.buffer)

            val borderWidth = 5f // Adjust the border width as needed

            var j = 0
            while (j < buffer.size()) {
                if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) {
                    j += 4
                    continue
                }
                if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j])) break

                // Draw the bar border
                mRenderPaint.style = Paint.Style.STROKE
                mRenderPaint.strokeWidth = borderWidth
                mRenderPaint.color = Color.BLACK // Set your desired border color
                c.drawRect(
                    buffer.buffer[j] + borderWidth / 2, // Adjust position for the border width
                    buffer.buffer[j + 1] + borderWidth / 2, // Adjust position for the border width
                    buffer.buffer[j + 2] - borderWidth / 2, // Adjust position for the border width
                    buffer.buffer[j + 3] - borderWidth / 2, // Adjust position for the border width
                    mRenderPaint
                )
                mRenderPaint.style = Paint.Style.FILL // Reset the paint style

                // Draw the bar
                if (mRadius > 0) {
                    val path: Path = RoundedRect(
                        buffer.buffer[j],
                        buffer.buffer[j + 1],
                        buffer.buffer[j + 2],
                        buffer.buffer[j + 3],
                        25f,
                        25f,
                        true,
                        true,
                        false,
                        false
                    )
                    c.drawPath(path, mRenderPaint)
                } else {
                    c.drawRect(
                        buffer.buffer[j],
                        buffer.buffer[j + 1],
                        buffer.buffer[j + 2],
                        buffer.buffer[j + 3],
                        mRenderPaint
                    )
                }
                j += 4
            }
        }
    }

Fact:

we draw the border around each bar by adjusting the position and style of the mRenderPaint. The borderWidth variable controls the width of the border, and you can change the color by setting the mRenderPaint.color to your desired border color.