Reputation: 2839
I want to have different value formatters for top and bottom xAxis to achieve effect similar to this:
Upvotes: 1
Views: 992
Reputation: 2839
Since I haven't been able to find a solution to this on StackOverflow I decided to post my own.
To do this we have to provide custom implementation of XAxisRenderer
:
class DoubleXLabelAxisRenderer(
viewPortHandler: ViewPortHandler,
xAxis: XAxis,
transformer: Transformer,
private val topValueFormatter: IAxisValueFormatter) : XAxisRenderer(viewPortHandler, xAxis, transformer) {
override fun renderAxisLabels(c: Canvas) {
if (!mXAxis.isEnabled || !mXAxis.isDrawLabelsEnabled)
return
val yoffset = mXAxis.yOffset
mAxisLabelPaint.typeface = mXAxis.typeface
mAxisLabelPaint.textSize = mXAxis.textSize
mAxisLabelPaint.color = mXAxis.textColor
val pointF = MPPointF.getInstance(0f, 0f)
if (mXAxis.position == XAxis.XAxisPosition.TOP) {
pointF.x = 0.5f
pointF.y = 1.0f
drawLabels(c, mViewPortHandler.contentTop() - yoffset, pointF)
} else if (mXAxis.position == XAxis.XAxisPosition.TOP_INSIDE) {
pointF.x = 0.5f
pointF.y = 1.0f
drawLabels(c, mViewPortHandler.contentTop() + yoffset + mXAxis.mLabelRotatedHeight.toFloat(), pointF)
} else if (mXAxis.position == XAxis.XAxisPosition.BOTTOM) {
pointF.x = 0.5f
pointF.y = 0.0f
drawLabels(c, mViewPortHandler.contentBottom() + yoffset, pointF)
} else if (mXAxis.position == XAxis.XAxisPosition.BOTTOM_INSIDE) {
pointF.x = 0.5f
pointF.y = 0.0f
drawLabels(c, mViewPortHandler.contentBottom() - yoffset - mXAxis.mLabelRotatedHeight.toFloat(), pointF)
} else { // BOTH SIDED
pointF.x = 0.5f
pointF.y = 1.0f
drawLabelsTop(c, mViewPortHandler.contentTop() - yoffset, pointF)
pointF.x = 0.5f
pointF.y = 0.0f
drawLabels(c, mViewPortHandler.contentBottom() + yoffset, pointF)
}
MPPointF.recycleInstance(pointF)
}
private fun drawLabelsTop(c: Canvas, pos: Float, anchor: MPPointF) {
val labelRotationAngleDegrees = mXAxis.labelRotationAngle
val centeringEnabled = mXAxis.isCenterAxisLabelsEnabled
val positions = FloatArray(mXAxis.mEntryCount * 2)
for(i in 0 until positions.size step 2) {
if (centeringEnabled) {
positions[i] = mXAxis.mCenteredEntries[i / 2]
} else {
positions[i] = mXAxis.mEntries[i / 2]
}
}
mTrans.pointValuesToPixel(positions)
for(i in 0 until positions.size step 2) {
var x = positions[i]
if (mViewPortHandler.isInBoundsX(x)) {
val label = topValueFormatter.getFormattedValue(mXAxis.mEntries[i / 2], mXAxis)
if (mXAxis.isAvoidFirstLastClippingEnabled) {
if (i == mXAxis.mEntryCount - 1 && mXAxis.mEntryCount > 1) {
val width = Utils.calcTextWidth(mAxisLabelPaint, label).toFloat()
if (width > mViewPortHandler.offsetRight() * 2 && x + width > mViewPortHandler.chartWidth)
x -= width / 2
} else if (i == 0) {
val width = Utils.calcTextWidth(mAxisLabelPaint, label).toFloat()
x += width / 2
}
}
drawLabel(c, label, x, pos, anchor, labelRotationAngleDegrees)
}
}
}
}
And then set it on our chart:
chart.setXAxisRenderer(
DoubleXLabelAxisRenderer(
chart.viewPortHandler,
chart.xAxis,
chart.getTransformer(YAxis.AxisDependency.LEFT),
IAxisValueFormatter { value, axis -> "someCustomValueForTopLabel" }))
And of course or xAxis position should be set to both sides:
chart.xAxis.position = XAxis.XAxisPosition.BOTH_SIDED
I hope someone with this problem will find this answer helpful
Upvotes: 3