24

I am trying to create a chart like below, For my android application using MPAndroidChart. I am unable to figure out, how to make the bar chart's edges as round edged. It always comes as square edge.

enter image description here

So can you please suggest me what I should do?

In advance thanks for your help.

syed imty
  • 1,018
  • 1
  • 9
  • 27

9 Answers9

35

I try combined @mallaudin and @Janusz Hain code. It's working now, Thanks you!!! here's my code

public class CustomBarChartRender extends BarChartRenderer {

private RectF mBarShadowRectBuffer = new RectF();

private int mRadius;

public CustomBarChartRender(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
    super(chart, animator, viewPortHandler);
}

public void setRadius(int mRadius) {
    this.mRadius = mRadius;
}

protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {

    Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
    mBarBorderPaint.setColor(dataSet.getBarBorderColor());
    mBarBorderPaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getBarBorderWidth()));
    mShadowPaint.setColor(dataSet.getBarShadowColor());
    boolean drawBorder = dataSet.getBarBorderWidth() > 0f;

    float phaseX = mAnimator.getPhaseX();
    float phaseY = mAnimator.getPhaseY();

    if (mChart.isDrawBarShadowEnabled()) {
        mShadowPaint.setColor(dataSet.getBarShadowColor());

        BarData barData = mChart.getBarData();

        float barWidth = barData.getBarWidth();
        float barWidthHalf = barWidth / 2.0f;
        float x;

        int i = 0;
        double count = Math.min(Math.ceil((int) (double) ((float) dataSet.getEntryCount() * phaseX)), dataSet.getEntryCount());
        while (i < count) {

            BarEntry e = dataSet.getEntryForIndex(i);

            x = e.getX();

            mBarShadowRectBuffer.left = x - barWidthHalf;
            mBarShadowRectBuffer.right = x + barWidthHalf;

            trans.rectValueToPixel(mBarShadowRectBuffer);

            if (!mViewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right)) {
                i++;
                continue;
            }

            if (!mViewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left))
                break;

            mBarShadowRectBuffer.top = mViewPortHandler.contentTop();
            mBarShadowRectBuffer.bottom = mViewPortHandler.contentBottom();

            c.drawRoundRect(mBarRect, mRadius, mRadius, mShadowPaint);
            i++;
        }
    }

    // initialize the buffer
    BarBuffer buffer = mBarBuffers[index];
    buffer.setPhases(phaseX, phaseY);
    buffer.setDataSet(index);
    buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
    buffer.setBarWidth(mChart.getBarData().getBarWidth());

    buffer.feed(dataSet);

    trans.pointValuesToPixel(buffer.buffer);

    boolean isSingleColor = dataSet.getColors().size() == 1;

    if (isSingleColor) {
        mRenderPaint.setColor(dataSet.getColor());
    }

    int j = 0;
    while (j < buffer.size()) {

        if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2])) {
            j += 4;
            continue;
        }

        if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
            break;

        if (!isSingleColor) {
            // Set the color for the currently drawn value. If the index
            // is out of bounds, reuse colors.
            mRenderPaint.setColor(dataSet.getColor(j / 4));
        }

        if (dataSet.getGradientColor() != null) {
            GradientColor gradientColor = dataSet.getGradientColor();
            mRenderPaint.setShader(new LinearGradient(
                    buffer.buffer[j],
                    buffer.buffer[j + 3],
                    buffer.buffer[j],
                    buffer.buffer[j + 1],
                    gradientColor.getStartColor(),
                    gradientColor.getEndColor(),
                    android.graphics.Shader.TileMode.MIRROR));
        }

        if (dataSet.getGradientColors() != null) {
            mRenderPaint.setShader(new LinearGradient(
                    buffer.buffer[j],
                    buffer.buffer[j + 3],
                    buffer.buffer[j],
                    buffer.buffer[j + 1],
                    dataSet.getGradientColor(j / 4).getStartColor(),
                    dataSet.getGradientColor(j / 4).getEndColor(),
                    Shader.TileMode.MIRROR));
        }
        Path path2 = roundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                buffer.buffer[j + 3]), mRadius, mRadius, true, true, false, false);
        c.drawPath(path2, mRenderPaint);
        if (drawBorder) {
            Path path = roundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                    buffer.buffer[j + 3]), mRadius, mRadius, true, true, false, false);
            c.drawPath(path, mBarBorderPaint);
        }
        j += 4;
    }

}

private Path roundRect(RectF rect, float rx, float ry, boolean tl, boolean tr, boolean br, boolean bl) {
    float top = rect.top;
    float left = rect.left;
    float right = rect.right;
    float bottom = rect.bottom;
    Path path = new Path();
    if (rx < 0) rx = 0;
    if (ry < 0) ry = 0;
    float width = right - left;
    float height = bottom - top;
    if (rx > width / 2) rx = width / 2;
    if (ry > height / 2) ry = height / 2;
    float widthMinusCorners = (width - (2 * rx));
    float heightMinusCorners = (height - (2 * ry));

    path.moveTo(right, top + ry);
    if (tr)
        path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
    else {
        path.rLineTo(0, -ry);
        path.rLineTo(-rx, 0);
    }
    path.rLineTo(-widthMinusCorners, 0);
    if (tl)
        path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
    else {
        path.rLineTo(-rx, 0);
        path.rLineTo(0, ry);
    }
    path.rLineTo(0, heightMinusCorners);

    if (bl)
        path.rQuadTo(0, ry, rx, ry);//bottom-left corner
    else {
        path.rLineTo(0, ry);
        path.rLineTo(rx, 0);
    }

    path.rLineTo(widthMinusCorners, 0);
    if (br)
        path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
    else {
        path.rLineTo(rx, 0);
        path.rLineTo(0, -ry);
    }

    path.rLineTo(0, -heightMinusCorners);

    path.close();//Given close, last lineto can be removed.

    return path;
}}

In other class:

CustomBarChartRender barChartRender = new CustomBarChartRender(barChart,barChart.getAnimator(), barChart.getViewPortHandler());
    barChartRender.setRadius(20);
    barChart.setRenderer(barChartRender);
duc tan
  • 351
  • 1
  • 3
  • 3
16

I've implemented a solution to achieve that straight on the library itself.

Firstly create an attrs.xml adding a new attribute to use on your chart view. Something like this:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="BarChart">
        <attr name="radius" format="integer" />
    </declare-styleable>
</resources>

Then edit the method called drawDataSet on the BarChartRenderer:

protected void drawDataSet(Canvas c, BarDataSet dataSet, int index) {

    Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());

    mShadowPaint.setColor(dataSet.getBarShadowColor());

    float phaseX = mAnimator.getPhaseX();
    float phaseY = mAnimator.getPhaseY();

    List<BarEntry> entries = dataSet.getYVals();

    // initialize the buffer
    BarBuffer buffer = mBarBuffers[index];
    buffer.setPhases(phaseX, phaseY);
    buffer.setBarSpace(dataSet.getBarSpace());
    buffer.setDataSet(index);
    buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));

    buffer.feed(entries);

    trans.pointValuesToPixel(buffer.buffer);

    // if multiple colors
    if (dataSet.getColors().size() > 1) {

        for (int j = 0; j < buffer.size(); j += 4) {

            if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                continue;

            if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                break;

            if (mChart.isDrawBarShadowEnabled()) {
                if (mRadius > 0)
                    c.drawRoundRect(new 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.setColor(dataSet.getColor(j / 4));
            if (mRadius > 0)
                c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3]), mRadius, mRadius, mRenderPaint);
            else
                c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3], mRenderPaint);
        }
    } else {

        mRenderPaint.setColor(dataSet.getColor());

        for (int j = 0; j < buffer.size(); j += 4) {

            if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                continue;

            if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                break;

            if (mChart.isDrawBarShadowEnabled()) {
                if (mRadius > 0)
                    c.drawRoundRect(new 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)
                c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3]), mRadius, mRadius, mRenderPaint);
            else
                c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3], mRenderPaint);
        }
    }
}

By doing this you're changing the rectangle but not its highlight, so change this bit of code on the drawHighlighted method:

if (mRadius > 0)
      c.drawRoundRect(mBarRect, mRadius, mRadius, mHighlightPaint);
else
      c.drawRect(mBarRect, mHighlightPaint);

To get the attribute from the xml file onto this render you need to add a set method as well:

public void setRadius (int radius) {
        mRadius = radius;
}

Finally create a new constructor on the BarChart object to grab the radius attribute:

public BarChart(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRadius = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto", "radius", 0);
        ((BarChartRenderer)mRenderer).setRadius(mRadius);
    }

And voila! Happy coding :)

RicardoSousaDev
  • 893
  • 9
  • 9
9

created a complete gist from last code of MPAndroidChart

https://gist.github.com/xanscale/e971cc4f2f0712a8a3bcc35e85325c27

Alessandro Scarozza
  • 4,273
  • 6
  • 31
  • 39
  • Can you show the code from where you are calling this gist ? I am not getting how will you pass data to this RoundedBarChart class and will this code work will negative values of barchart in horizontal bar chart? – sak Dec 19 '19 at 06:07
  • you can use as normal BarChart, just replaced drawRect with drawRoundRect – Alessandro Scarozza Dec 19 '19 at 13:26
  • Please have a look at my question https://stackoverflow.com/questions/59405125/round-corners-for-both-negative-and-positive-bars-of-horizontal-bar-chart-using?noredirect=1#comment104998349_59405125 – sak Dec 20 '19 at 01:52
6

1) Add the following class:

public class RoundedBarChart extends BarChartRenderer {


    public RoundedBarChart(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
        super(chart, animator, viewPortHandler);
    }

    private float mRadius=5f;

    public void setmRadius(float mRadius) {
        this.mRadius = mRadius;
    }

    @Override
    protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {

     
            Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());

            mShadowPaint.setColor(dataSet.getBarShadowColor());

            float phaseX = mAnimator.getPhaseX();
            float phaseY = mAnimator.getPhaseY();



            if(mBarBuffers!=null){
                // initialize the buffer
                BarBuffer buffer = mBarBuffers[index];
                buffer.setPhases(phaseX, phaseY);
                buffer.setDataSet(index);
                buffer.setBarWidth(mChart.getBarData().getBarWidth());
                buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));

                buffer.feed(dataSet);

                trans.pointValuesToPixel(buffer.buffer);

                // if multiple colors
                if (dataSet.getColors().size() > 1) {

                    for (int j = 0; j < buffer.size(); j += 4) {

                        if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                            continue;

                        if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                            break;

                        if (mChart.isDrawBarShadowEnabled()) {
                            if (mRadius > 0)
                                c.drawRoundRect(new 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.setColor(dataSet.getColor(j / 4));
                        if (mRadius > 0){

                            Path path = RoundedRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2] , buffer.buffer[j + 3] , 15,15, 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);


                    }
                } else {

                    mRenderPaint.setColor(dataSet.getColor());

                    for (int j = 0; j < buffer.size(); j += 4) {

                        if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                            continue;

                        if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                            break;

                        if (mChart.isDrawBarShadowEnabled()) {
                            if (mRadius > 0)
                                c.drawRoundRect(new 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){
                            Path path = RoundedRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2] , buffer.buffer[j + 3] , 15,15, 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);
                    }
                }
            }
        
    }
    public static Path RoundedRect(
            float left, float top, float right, float bottom, float rx, float ry,
            boolean tl, boolean tr, boolean br, boolean bl
    ){
        Path path = new Path();
        if (rx < 0) rx = 0;
        if (ry < 0) ry = 0;
        float width = right - left;
        float height = bottom - top;
        if (rx > width / 2) rx = width / 2;
        if (ry > height / 2) ry = height / 2;
        float widthMinusCorners = (width - (2 * rx));
        float heightMinusCorners = (height - (2 * ry));

        path.moveTo(right, top + ry);
        if (tr)
            path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
        else{
            path.rLineTo(0, -ry);
            path.rLineTo(-rx,0);
        }
        path.rLineTo(-widthMinusCorners, 0);
        if (tl)
            path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
        else{
            path.rLineTo(-rx, 0);
            path.rLineTo(0,ry);
        }
        path.rLineTo(0, heightMinusCorners);

        if (bl)
            path.rQuadTo(0, ry, rx, ry);//bottom-left corner
        else{
            path.rLineTo(0, ry);
            path.rLineTo(rx,0);
        }

        path.rLineTo(widthMinusCorners, 0);
        if (br)
            path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
        else{
            path.rLineTo(rx,0);
            path.rLineTo(0, -ry);
        }

        path.rLineTo(0, -heightMinusCorners);

        path.close();//Given close, last lineto can be removed.

        return path;
    }
}

2) Use barChart.renderer = RoundedBarChart(barChart, barChart.animator, barChart.viewPortHandler)

xKobalt
  • 1,498
  • 2
  • 13
  • 19
SundravelS
  • 61
  • 1
  • 2
3

For this purpose you need to custimze your BarchartRenderer class....

Step 1

Make a custom class (if you are not adding mpchart as module ) Copy paste all the code from BarchartRenderer class into ur custom class. Now replace your drawDataSet method with mine in ur custom class.....

Step 2

After that setRender to the custom class you just made.

Kotlin Code for setting render Java code will be kinda same.

In the end enjoy

BarChartCustomRenderer customRenderer = BarChartCustomRenderer(mDashBoardBinding.topperChart, mDashBoardBinding.topperChart.getAnimator(), mDashBoardBinding.topperChart.getViewPortHandler());

topperChart.setRenderer(customRenderer);

drawDataSet:

protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {

            Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());

            mShadowPaint.setColor(dataSet.getBarShadowColor());

            float phaseX = mAnimator.getPhaseX();
            float phaseY = mAnimator.getPhaseY();


            // initialize the buffer
            BarBuffer buffer = mBarBuffers[index];
            buffer.setPhases(phaseX, phaseY);
            buffer.setDataSet(index);
            buffer.setBarWidth(mChart.getBarData().getBarWidth());
            buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));

            buffer.feed(dataSet);

            trans.pointValuesToPixel(buffer.buffer);

            // if multiple colors
            if (dataSet.getColors().size() > 1) {

                for (int j = 0; j < buffer.size(); j += 4) {

                    if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                        continue;

                    if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                        break;

                    if (mChart.isDrawBarShadowEnabled()) {
                        if (mRadius > 0)
                            c.drawRoundRect(new 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.setColor(dataSet.getColor(j / 4));
                    if (mRadius > 0)
                        c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                                buffer.buffer[j + 3]), mRadius, mRadius, mRenderPaint);
                    else
                        c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                                buffer.buffer[j + 3], mRenderPaint);
                }
            } else {

                mRenderPaint.setColor(dataSet.getColor());

                for (int j = 0; j < buffer.size(); j += 4) {

                    if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                        continue;

                    if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                        break;

                    if (mChart.isDrawBarShadowEnabled()) {
                        if (mRadius > 0)
                            c.drawRoundRect(new 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)
                        c.drawRoundRect(new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                                buffer.buffer[j + 3]), mRadius, mRadius, mRenderPaint);
                    else
                        c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                                buffer.buffer[j + 3], mRenderPaint);
                }
            }
        }
SolArabehety
  • 8,467
  • 5
  • 38
  • 42
2

I have created class based on above for actual library (which has different code for drawing) - v3.1.0-alpha

class RoundedBarChartRenderer(chart: BarDataProvider,
                          animator: ChartAnimator,
                          viewPortHandler: ViewPortHandler,
                          private val mRadius: Float) :
    BarChartRenderer(chart, animator, viewPortHandler) {

private val mBarShadowRectBuffer = RectF()

override fun drawDataSet(c: Canvas?, dataSet: IBarDataSet?, index: Int) {

    if (c == null || dataSet == null) return

    val trans = mChart.getTransformer(dataSet.axisDependency)

    mBarBorderPaint.color = dataSet.barBorderColor
    mBarBorderPaint.strokeWidth = Utils.convertDpToPixel(dataSet.barBorderWidth)

    val drawBorder = dataSet.barBorderWidth > 0f

    val phaseX = mAnimator.phaseX
    val phaseY = mAnimator.phaseY

    // draw the bar shadow before the values
    if (mChart.isDrawBarShadowEnabled) {
        mShadowPaint.color = dataSet.barShadowColor

        val barData = mChart.barData

        val barWidth = barData.barWidth
        val barWidthHalf = barWidth / 2.0f
        var x: Float

        var i = 0
        val count = Math.min(Math.ceil((dataSet.entryCount.toFloat() * phaseX).toDouble()).toInt(), dataSet.entryCount)
        while (i < count) {

            val e = dataSet.getEntryForIndex(i)

            x = e.x

            mBarShadowRectBuffer.left = x - barWidthHalf
            mBarShadowRectBuffer.right = x + barWidthHalf

            trans.rectValueToPixel(mBarShadowRectBuffer)

            if (!mViewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right)) {
                i++
                continue
            }

            if (!mViewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left))
                break

            mBarShadowRectBuffer.top = mViewPortHandler.contentTop()
            mBarShadowRectBuffer.bottom = mViewPortHandler.contentBottom()

            c.drawRoundRect(mBarRect, mRadius, mRadius, mShadowPaint)
            i++
        }
    }

    // initialize the buffer
    val buffer = mBarBuffers[index]
    buffer.setPhases(phaseX, phaseY)
    buffer.setDataSet(index)
    buffer.setInverted(mChart.isInverted(dataSet.axisDependency))
    buffer.setBarWidth(mChart.barData.barWidth)

    buffer.feed(dataSet)

    trans.pointValuesToPixel(buffer.buffer)

    val isSingleColor = dataSet.colors.size == 1

    if (isSingleColor) {
        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 (!isSingleColor) {
            // Set the color for the currently drawn value. If the index
            // is out of bounds, reuse colors.
            mRenderPaint.color = dataSet.getColor(j / 4)
        }

        if (dataSet.gradientColor != null) {
            val gradientColor = dataSet.gradientColor
            mRenderPaint.shader = LinearGradient(
                    buffer.buffer[j],
                    buffer.buffer[j + 3],
                    buffer.buffer[j],
                    buffer.buffer[j + 1],
                    gradientColor.startColor,
                    gradientColor.endColor,
                    android.graphics.Shader.TileMode.MIRROR)
        }

        if (dataSet.gradientColors != null) {
            mRenderPaint.shader = LinearGradient(
                    buffer.buffer[j],
                    buffer.buffer[j + 3],
                    buffer.buffer[j],
                    buffer.buffer[j + 1],
                    dataSet.getGradientColor(j / 4).startColor,
                    dataSet.getGradientColor(j / 4).endColor,
                    Shader.TileMode.MIRROR)
        }


        c.drawRoundRect(RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                buffer.buffer[j + 3]), mRadius, mRadius, mRenderPaint)

        if (drawBorder) {
            c.drawRoundRect(RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                    buffer.buffer[j + 3]), mRadius, mRadius, mBarBorderPaint)
        }
        j += 4
    }
}

}

Janusz Hain
  • 597
  • 5
  • 18
2

You can use @Xan provided gist and if you want both sides round-edged you can implement the gist and provide the following property to bar chart view

barChartView.axisLeft.axisMinimum = 0f;

this will make both sides rounded.

iamsr
  • 314
  • 2
  • 6
  • Your single line of code does not taking effect to make both the corners of Bar rounded!!!!! – Jaimin Modi May 18 '21 at 14:12
  • had you implemented the @Xan provided gist too or not? Implementing that gist will give you one side round edge and adding this line of code will make it both side rounded. – iamsr May 19 '21 at 06:52
1

The above answer is right but it doesn't work if graph has negative values.

I have picked the rounded rectangle code form this answer.

Steps

  1. Add the following method to BarChartRenderer class

    /**
     * @param rect rectangle to be rounded
     * @param rx   radius x
    * @param ry   radius y
    * @param tl   true - for rounding top-left corner
    * @param tr   true - for rounding top-right corner
    * @param br   true - for rounding bottom-right corner
    * @param bl   true - for rounding bottom-left corner
    * @return path
    */
    private Path roundRect(RectF rect, float rx, float ry, boolean tl, boolean tr, boolean br, boolean bl) {
    float top = rect.top;
    float left = rect.left;
    float right = rect.right;
    float bottom = rect.bottom;
    Path path = new Path();
    if (rx < 0) rx = 0;
    if (ry < 0) ry = 0;
    float width = right - left;
    float height = bottom - top;
    if (rx > width / 2) rx = width / 2;
    if (ry > height / 2) ry = height / 2;
    float widthMinusCorners = (width - (2 * rx));
    float heightMinusCorners = (height - (2 * ry));
    
    path.moveTo(right, top + ry);
    if (tr)
        path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
    else {
        path.rLineTo(0, -ry);
        path.rLineTo(-rx, 0);
    }
    path.rLineTo(-widthMinusCorners, 0);
    if (tl)
        path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
    else {
        path.rLineTo(-rx, 0);
        path.rLineTo(0, ry);
    }
    path.rLineTo(0, heightMinusCorners);
    
    if (bl)
        path.rQuadTo(0, ry, rx, ry);//bottom-left corner
    else {
        path.rLineTo(0, ry);
        path.rLineTo(rx, 0);
    }
    
    path.rLineTo(widthMinusCorners, 0);
    if (br)
        path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
    else {
        path.rLineTo(rx, 0);
        path.rLineTo(0, -ry);
    }
    
    path.rLineTo(0, -heightMinusCorners);
    
    path.close();//Given close, last lineto can be removed.
    
    return path;
    }
    
  2. In drawDataSet(Canvas c, IBarDataSet dataSet, int index) method, replace all drawRoundRect methods with the following code

     Path path = roundRect(yourRect, yourRadius, yourRadius, true, true, false, false);
                    canvas.drawPath(path, yourPaint);
    
mallaudin
  • 4,744
  • 3
  • 36
  • 68
  • 1
    Thanks. In my case,Y axis has always both positive and negative values. For better understanding, You can check the example of Stacked Bar Chart Negative in MPChart. I've did something and it looks like this. https://imgur.com/a/wDeLu I want the zero line to be aligned properly. Any idea regarding this? – DroidLearner Mar 25 '18 at 03:40
  • I need to do call roundRect method with (true,true,false,false) for positive values, and for negative values (false,false,true,true). How can I get Y axis values in drawRectmethod() so that i can check based on the values. Am i right? – DroidLearner Mar 25 '18 at 03:50
  • @DroidLearner i have same issue to fixed out do you solve that issue. if you do can you please share the code snippet or procedures thank you. – Randika Wanninayaka Mar 30 '21 at 17:09
1

with @duc tan 's answer,I solved this question,but his code didnt handle highlight.I add below code to solved highlight corner.

public void drawHighlighted(Canvas c, Highlight[] indices) {
        BarData barData = mChart.getBarData();

        for (Highlight high : indices) {

            IBarDataSet set = barData.getDataSetByIndex(high.getDataSetIndex());

            if (set == null || !set.isHighlightEnabled()) {
                continue;
            }

            BarEntry e = set.getEntryForXValue(high.getX(), high.getY());

            if (!isInBoundsX(e, set)) {
                continue;
            }

            Transformer trans = mChart.getTransformer(set.getAxisDependency());

            mHighlightPaint.setColor(set.getHighLightColor());
            mHighlightPaint.setAlpha(set.getHighLightAlpha());

            boolean isStack = high.getStackIndex() >= 0 && e.isStacked();

            final float y1;
            final float y2;

            if (isStack) {

                if (mChart.isHighlightFullBarEnabled()) {

                    y1 = e.getPositiveSum();
                    y2 = -e.getNegativeSum();

                } else {

                    Range range = e.getRanges()[high.getStackIndex()];

                    y1 = range.from;
                    y2 = range.to;
                }

            } else {
                y1 = e.getY();
                y2 = 0.f;
            }

            prepareBarHighlight(e.getX(), y1, y2, barData.getBarWidth() / 2f, trans);

            setHighlightDrawPos(high, mBarRect);

            Path path2 = roundRect(new RectF(mBarRect.left, mBarRect.top, mBarRect.right,
                    mBarRect.bottom), mRadius, mRadius, true, true, false, false);

            c.drawPath(path2, mHighlightPaint);
        }
    }
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Rickon Gao
  • 116
  • 6