I need change bars view in barchart in MPAndroidChart like this... that's how it should be Is it possible to set custom bar drawable, or just smooth the corners, or something like this?
My code:
fun barChart(
activity: Activity,
chart: BarChart,
entries: ArrayList<BarEntry>,
columnsNames: ArrayList<String>,
colors: ArrayList<Int>,
) {
val colorsTemplate = intArrayOf(
Color.rgb(74, 160, 150), Color.rgb(74, 160, 150), Color.rgb(74, 160, 150),
Color.rgb(74, 160, 150), Color.rgb(74, 160, 150)
)
val colors: ArrayList<Int> = ArrayList()
for (color in colorsTemplate) {
colors.add(color)
}
val dataSet = BarDataSet(entries, "")
val decimalFormat = DecimalFormat("0.##")
dataSet.setValueFormatter(object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return decimalFormat.format(value)
}
})
dataSet.colors = colors
val data = BarData(dataSet)
data.barWidth = 0.5f
data.setDrawValues(true)
chart.setData(data)
chart.setAutoScaleMinMaxEnabled(true)
val xAxis = chart.getXAxis()
xAxis.valueFormatter = IndexAxisValueFormatter(columnsNames)
xAxis.position = (XAxis.XAxisPosition.BOTTOM)
xAxis.setDrawGridLines(false)
xAxis.setDrawAxisLine(false)
xAxis.granularity = 1f
xAxis.labelCount = columnsNames!!.size
xAxis.labelRotationAngle = 360f
chart.legend.isEnabled = false
chart.description.isEnabled = false
chart.axisRight.isEnabled = false
chart.axisLeft.labelCount = 3
chart.axisLeft.axisMinimum = 0f
chart.animateY(1000)
chart.invalidate()
}
Some time after the found solution I am writing an answer to my own question, maybe it will be useful to someone. Thanks gioravered for the tip
This is code for your chart:
val barChartRender =
RoundedBarChartRender(chart, chart.animator, chart.viewPortHandler)
barChartRender.initBuffers()
barChartRender.setRadius(20)
chart.renderer = barChartRender
And this is the code of a new sub class, which render the rounding:
class RoundedBarChartRender(
chart: BarDataProvider?,
animator: ChartAnimator?,
viewPortHandler: ViewPortHandler?
) : BarChartRenderer(chart, animator, viewPortHandler) {
private val mBarShadowRectBuffer = RectF()
private var mRadius = 0
fun setRadius(mRadius: Int) {
this.mRadius = mRadius
}
override fun drawDataSet(c: Canvas, dataSet: IBarDataSet, index: Int) {
val trans = mChart.getTransformer(dataSet.axisDependency)
mBarBorderPaint.color = dataSet.barBorderColor
mBarBorderPaint.strokeWidth = Utils.convertDpToPixel(dataSet.barBorderWidth)
mShadowPaint.color = dataSet.barShadowColor
val drawBorder = dataSet.barBorderWidth > 0f
val phaseX = mAnimator.phaseX
val phaseY = mAnimator.phaseY
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().toDouble()
), dataSet.entryCount.toDouble()
)
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.toFloat(), mRadius.toFloat(), 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,
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
)
}
val path2 = roundRect(
RectF(
buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3]
), mRadius.toFloat(), mRadius.toFloat(), true, true, false, false
)
c.drawPath(path2, mRenderPaint)
if (drawBorder) {
val path = roundRect(
RectF(
buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3]
), mRadius.toFloat(), mRadius.toFloat(), true, true, false, false
)
c.drawPath(path, mBarBorderPaint)
}
j += 4
}
}
private fun roundRect(
rect: RectF,
rx: Float,
ry: Float,
tl: Boolean,
tr: Boolean,
br: Boolean,
bl: Boolean
): Path {
var rx = rx
var ry = ry
val top = rect.top
val left = rect.left
val right = rect.right
val bottom = rect.bottom
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 lineto can be removed.
return path
}
}