的
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
apply(from = rootProject.file("gradle/configure-android.gradle"))
|
||||
apply(from = rootProject.file("gradle/configure-compose.gradle"))
|
||||
apply(from = rootProject.file("gradle/jitpack-publish.gradle"))
|
||||
|
||||
dependencies {
|
||||
api(project(":lib:common"))
|
||||
|
||||
implementation(Kotlin.stdLib)
|
||||
|
||||
implementation(Compose.animation)
|
||||
implementation(Compose.core)
|
||||
implementation(Compose.layout)
|
||||
implementation(Compose.foundation)
|
||||
implementation(Compose.material)
|
||||
implementation(Compose.runtime)
|
||||
debugImplementation(Compose.tooling)
|
||||
}
|
||||
android {
|
||||
namespace = "com.github.tehras.charts.bar"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest />
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.github.tehras.charts.bar
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.AnimationSpec
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import com.github.tehras.charts.bar.BarChartUtils.axisAreas
|
||||
import com.github.tehras.charts.bar.BarChartUtils.barDrawableArea
|
||||
import com.github.tehras.charts.bar.BarChartUtils.forEachWithArea
|
||||
import com.github.tehras.charts.bar.renderer.bar.BarDrawer
|
||||
import com.github.tehras.charts.bar.renderer.bar.SimpleBarDrawer
|
||||
import com.github.tehras.charts.bar.renderer.label.LabelDrawer
|
||||
import com.github.tehras.charts.bar.renderer.label.SimpleValueDrawer
|
||||
import com.github.tehras.charts.bar.renderer.xaxis.SimpleXAxisDrawer
|
||||
import com.github.tehras.charts.bar.renderer.xaxis.XAxisDrawer
|
||||
import com.github.tehras.charts.bar.renderer.yaxis.SimpleYAxisDrawer
|
||||
import com.github.tehras.charts.bar.renderer.yaxis.YAxisDrawer
|
||||
import com.github.tehras.charts.piechart.animation.simpleChartAnimation
|
||||
|
||||
@Composable
|
||||
fun BarChart(
|
||||
barChartData: BarChartData,
|
||||
modifier: Modifier = Modifier,
|
||||
animation: AnimationSpec<Float> = simpleChartAnimation(),
|
||||
barDrawer: BarDrawer = SimpleBarDrawer(),
|
||||
xAxisDrawer: XAxisDrawer = SimpleXAxisDrawer(),
|
||||
yAxisDrawer: YAxisDrawer = SimpleYAxisDrawer(),
|
||||
labelDrawer: LabelDrawer = SimpleValueDrawer()
|
||||
) {
|
||||
val transitionAnimation = remember(barChartData.bars) { Animatable(initialValue = 0f) }
|
||||
|
||||
LaunchedEffect(barChartData.bars) {
|
||||
transitionAnimation.animateTo(1f, animationSpec = animation)
|
||||
}
|
||||
|
||||
val progress = transitionAnimation.value
|
||||
|
||||
Canvas(modifier = modifier
|
||||
.fillMaxSize()
|
||||
.drawBehind {
|
||||
drawIntoCanvas { canvas ->
|
||||
val (xAxisArea, yAxisArea) = axisAreas(
|
||||
drawScope = this,
|
||||
totalSize = size,
|
||||
xAxisDrawer = xAxisDrawer,
|
||||
labelDrawer = labelDrawer
|
||||
)
|
||||
val barDrawableArea = barDrawableArea(xAxisArea)
|
||||
|
||||
// Draw yAxis line.
|
||||
yAxisDrawer.drawAxisLine(
|
||||
drawScope = this,
|
||||
canvas = canvas,
|
||||
drawableArea = yAxisArea
|
||||
)
|
||||
|
||||
// Draw xAxis line.
|
||||
xAxisDrawer.drawAxisLine(
|
||||
drawScope = this,
|
||||
canvas = canvas,
|
||||
drawableArea = xAxisArea
|
||||
)
|
||||
// Draw each bar.
|
||||
barChartData.forEachWithArea(
|
||||
this,
|
||||
barDrawableArea,
|
||||
progress,
|
||||
labelDrawer
|
||||
) { barArea, bar ->
|
||||
barDrawer.drawBar(
|
||||
drawScope = this,
|
||||
canvas = canvas,
|
||||
barArea = barArea,
|
||||
bar = bar
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
/**
|
||||
* Typically we could draw everything here, but because of the lack of canvas.drawText
|
||||
* APIs we have to use Android's `nativeCanvas` which seems to be drawn behind
|
||||
* Compose's canvas.
|
||||
*/
|
||||
drawIntoCanvas { canvas ->
|
||||
val (xAxisArea, yAxisArea) = axisAreas(
|
||||
drawScope = this,
|
||||
totalSize = size,
|
||||
xAxisDrawer = xAxisDrawer,
|
||||
labelDrawer = labelDrawer
|
||||
)
|
||||
val barDrawableArea = barDrawableArea(xAxisArea)
|
||||
|
||||
barChartData.forEachWithArea(
|
||||
this,
|
||||
barDrawableArea,
|
||||
progress,
|
||||
labelDrawer
|
||||
) { barArea, bar ->
|
||||
labelDrawer.drawLabel(
|
||||
drawScope = this,
|
||||
canvas = canvas,
|
||||
label = bar.label,
|
||||
barArea = barArea,
|
||||
xAxisArea = xAxisArea
|
||||
)
|
||||
}
|
||||
|
||||
yAxisDrawer.drawAxisLabels(
|
||||
drawScope = this,
|
||||
canvas = canvas,
|
||||
minValue = barChartData.minYValue,
|
||||
maxValue = barChartData.maxYValue,
|
||||
drawableArea = yAxisArea
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.github.tehras.charts.bar
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
data class BarChartData(
|
||||
val bars: List<Bar>,
|
||||
val padBy: Float = 10f,
|
||||
val startAtZero: Boolean = true
|
||||
) {
|
||||
init {
|
||||
require(padBy in 0f..100f)
|
||||
}
|
||||
|
||||
private val yMinMax: Pair<Float, Float>
|
||||
get() {
|
||||
val min = bars.minByOrNull { it.value }?.value ?: 0f
|
||||
val max = bars.maxByOrNull { it.value }?.value ?: 0f
|
||||
|
||||
return min to max
|
||||
}
|
||||
internal val maxYValue: Float =
|
||||
yMinMax.second + ((yMinMax.second - yMinMax.first) * padBy / 100f)
|
||||
internal val minYValue: Float
|
||||
get() {
|
||||
return if (startAtZero) {
|
||||
0f
|
||||
} else {
|
||||
yMinMax.first - ((yMinMax.second - yMinMax.first) * padBy / 100f)
|
||||
}
|
||||
}
|
||||
|
||||
val maxBarValue = bars.maxByOrNull { it.value }?.value ?: 0f
|
||||
|
||||
data class Bar(
|
||||
val value: Float,
|
||||
val color: Color,
|
||||
val label: String
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.github.tehras.charts.bar
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.github.tehras.charts.bar.renderer.label.LabelDrawer
|
||||
import com.github.tehras.charts.bar.renderer.xaxis.XAxisDrawer
|
||||
|
||||
internal object BarChartUtils {
|
||||
fun axisAreas(
|
||||
drawScope: DrawScope,
|
||||
totalSize: Size,
|
||||
xAxisDrawer: XAxisDrawer,
|
||||
labelDrawer: LabelDrawer
|
||||
): Pair<Rect, Rect> = with(drawScope) {
|
||||
// yAxis
|
||||
val yAxisTop = labelDrawer.requiredAboveBarHeight(drawScope)
|
||||
|
||||
// Either 50dp or 10% of the chart width.
|
||||
val yAxisRight = minOf(50.dp.toPx(), size.width * 10f / 100f)
|
||||
|
||||
// xAxis
|
||||
val xAxisRight = totalSize.width
|
||||
|
||||
// Measure the size of the text and line.
|
||||
val xAxisTop = totalSize.height - xAxisDrawer.requiredHeight(drawScope)
|
||||
|
||||
return Pair(
|
||||
Rect(yAxisRight, xAxisTop, xAxisRight, totalSize.height),
|
||||
Rect(0f, yAxisTop, yAxisRight, xAxisTop)
|
||||
)
|
||||
}
|
||||
|
||||
fun barDrawableArea(xAxisArea: Rect): Rect {
|
||||
return Rect(
|
||||
left = xAxisArea.left,
|
||||
top = 0f,
|
||||
right = xAxisArea.right,
|
||||
bottom = xAxisArea.top
|
||||
)
|
||||
}
|
||||
|
||||
fun BarChartData.forEachWithArea(
|
||||
drawScope: DrawScope,
|
||||
barDrawableArea: Rect,
|
||||
progress: Float,
|
||||
labelDrawer: LabelDrawer,
|
||||
block: (barArea: Rect, bar: BarChartData.Bar) -> Unit
|
||||
) {
|
||||
val totalBars = bars.size
|
||||
val widthOfBarArea = barDrawableArea.width / totalBars
|
||||
val offsetOfBar = widthOfBarArea * 0.2f
|
||||
|
||||
bars.forEachIndexed { index, bar ->
|
||||
val left = barDrawableArea.left + (index * widthOfBarArea)
|
||||
val height = barDrawableArea.height
|
||||
|
||||
val barHeight = (height - labelDrawer.requiredAboveBarHeight(drawScope)) * progress
|
||||
|
||||
val barArea = Rect(
|
||||
left = left + offsetOfBar,
|
||||
top = barDrawableArea.bottom - (bar.value / maxBarValue) * barHeight,
|
||||
right = left + widthOfBarArea - offsetOfBar,
|
||||
bottom = barDrawableArea.bottom
|
||||
)
|
||||
|
||||
block(barArea, bar)
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.github.tehras.charts.bar.renderer.bar
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import com.github.tehras.charts.bar.BarChartData
|
||||
|
||||
interface BarDrawer {
|
||||
fun drawBar(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
barArea: Rect,
|
||||
bar: BarChartData.Bar
|
||||
)
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.github.tehras.charts.bar.renderer.bar
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.Paint
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import com.github.tehras.charts.bar.BarChartData
|
||||
|
||||
class SimpleBarDrawer : BarDrawer {
|
||||
private val barPaint = Paint().apply {
|
||||
this.isAntiAlias = true
|
||||
}
|
||||
|
||||
override fun drawBar(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
barArea: Rect,
|
||||
bar: BarChartData.Bar
|
||||
) {
|
||||
canvas.drawRect(barArea, barPaint.apply {
|
||||
color = bar.color
|
||||
})
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.github.tehras.charts.bar.renderer.label
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
|
||||
interface LabelDrawer {
|
||||
fun requiredXAxisHeight(drawScope: DrawScope): Float = 0f
|
||||
fun requiredAboveBarHeight(drawScope: DrawScope): Float = 0f
|
||||
|
||||
fun drawLabel(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
label: String,
|
||||
barArea: Rect,
|
||||
xAxisArea: Rect
|
||||
)
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.github.tehras.charts.bar.renderer.label
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.github.tehras.charts.bar.renderer.label.SimpleValueDrawer.DrawLocation.Inside
|
||||
import com.github.tehras.charts.bar.renderer.label.SimpleValueDrawer.DrawLocation.Outside
|
||||
import com.github.tehras.charts.bar.renderer.label.SimpleValueDrawer.DrawLocation.XAxis
|
||||
import com.github.tehras.charts.piechart.utils.toLegacyInt
|
||||
|
||||
class SimpleValueDrawer(
|
||||
private val drawLocation: DrawLocation = Inside,
|
||||
private val labelTextSize: TextUnit = 12.sp,
|
||||
private val labelTextColor: Color = Color.Black
|
||||
) : LabelDrawer {
|
||||
private val _labelTextArea: Float? = null
|
||||
private val paint = android.graphics.Paint().apply {
|
||||
this.textAlign = android.graphics.Paint.Align.CENTER
|
||||
this.color = labelTextColor.toLegacyInt()
|
||||
}
|
||||
|
||||
override fun requiredAboveBarHeight(drawScope: DrawScope): Float = when (drawLocation) {
|
||||
Outside -> (3f / 2f) * labelTextHeight(drawScope)
|
||||
Inside,
|
||||
XAxis -> 0f
|
||||
}
|
||||
|
||||
override fun requiredXAxisHeight(drawScope: DrawScope): Float = when (drawLocation) {
|
||||
XAxis -> labelTextHeight(drawScope)
|
||||
Inside,
|
||||
Outside -> 0f
|
||||
}
|
||||
|
||||
override fun drawLabel(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
label: String,
|
||||
barArea: Rect,
|
||||
xAxisArea: Rect
|
||||
) = with(drawScope) {
|
||||
val xCenter = barArea.left + (barArea.width / 2)
|
||||
|
||||
val yCenter = when (drawLocation) {
|
||||
Inside -> (barArea.top + barArea.bottom) / 2
|
||||
Outside -> (barArea.top) - labelTextSize.toPx() / 2
|
||||
XAxis -> barArea.bottom + labelTextHeight(drawScope)
|
||||
}
|
||||
|
||||
canvas.nativeCanvas.drawText(label, xCenter, yCenter, paint(drawScope))
|
||||
}
|
||||
|
||||
private fun labelTextHeight(drawScope: DrawScope) = with(drawScope) {
|
||||
_labelTextArea ?: ((3f / 2f) * labelTextSize.toPx())
|
||||
}
|
||||
|
||||
private fun paint(drawScope: DrawScope) = with(drawScope) {
|
||||
paint.apply {
|
||||
this.textSize = labelTextSize.toPx()
|
||||
}
|
||||
}
|
||||
|
||||
enum class DrawLocation {
|
||||
Inside,
|
||||
Outside,
|
||||
XAxis
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.github.tehras.charts.bar.renderer.xaxis
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Paint
|
||||
import androidx.compose.ui.graphics.PaintingStyle
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
class SimpleXAxisDrawer(
|
||||
private val axisLineThickness: Dp = 1.dp,
|
||||
private val axisLineColor: Color = Color.Black
|
||||
) : XAxisDrawer {
|
||||
private val axisLinePaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = axisLineColor
|
||||
style = PaintingStyle.Stroke
|
||||
}
|
||||
|
||||
override fun requiredHeight(drawScope: DrawScope): Float = with(drawScope) {
|
||||
(3f / 2f) * axisLineThickness.toPx()
|
||||
}
|
||||
|
||||
override fun drawAxisLine(drawScope: DrawScope, canvas: Canvas, drawableArea: Rect) =
|
||||
with(drawScope) {
|
||||
val lineThickness = axisLineThickness.toPx()
|
||||
val y = drawableArea.top + (lineThickness / 2f)
|
||||
|
||||
canvas.drawLine(
|
||||
p1 = Offset(
|
||||
x = drawableArea.left,
|
||||
y = y
|
||||
),
|
||||
p2 = Offset(
|
||||
x = drawableArea.right,
|
||||
y = y
|
||||
),
|
||||
paint = axisLinePaint.apply {
|
||||
strokeWidth = lineThickness
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.github.tehras.charts.bar.renderer.xaxis
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
|
||||
interface XAxisDrawer {
|
||||
fun requiredHeight(drawScope: DrawScope): Float
|
||||
|
||||
fun drawAxisLine(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
drawableArea: Rect
|
||||
)
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.github.tehras.charts.bar.renderer.yaxis
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Paint
|
||||
import androidx.compose.ui.graphics.PaintingStyle
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.github.tehras.charts.piechart.utils.toLegacyInt
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
typealias LabelFormatter = (value: Float) -> String
|
||||
|
||||
class SimpleYAxisDrawer(
|
||||
private val labelTextSize: TextUnit = 12.sp,
|
||||
private val labelTextColor: Color = Color.Black,
|
||||
private val labelRatio: Int = 3,
|
||||
private val labelValueFormatter: LabelFormatter = { value -> "%.1f".format(value) },
|
||||
private val axisLineThickness: Dp = 1.dp,
|
||||
private val axisLineColor: Color = Color.Black
|
||||
) : YAxisDrawer {
|
||||
private val axisLinePaint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = axisLineColor
|
||||
style = PaintingStyle.Stroke
|
||||
}
|
||||
private val textPaint = android.graphics.Paint().apply {
|
||||
isAntiAlias = true
|
||||
color = labelTextColor.toLegacyInt()
|
||||
}
|
||||
private val textBounds = android.graphics.Rect()
|
||||
|
||||
override fun drawAxisLine(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
drawableArea: Rect
|
||||
) = with(drawScope) {
|
||||
val lineThickness = axisLineThickness.toPx()
|
||||
val x = drawableArea.right - (lineThickness / 2f)
|
||||
|
||||
canvas.drawLine(
|
||||
p1 = Offset(
|
||||
x = x,
|
||||
y = drawableArea.top
|
||||
),
|
||||
p2 = Offset(
|
||||
x = x,
|
||||
y = drawableArea.bottom
|
||||
),
|
||||
paint = axisLinePaint.apply {
|
||||
strokeWidth = lineThickness
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun drawAxisLabels(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
drawableArea: Rect,
|
||||
minValue: Float,
|
||||
maxValue: Float
|
||||
) = with(drawScope) {
|
||||
val labelPaint = textPaint.apply {
|
||||
textSize = labelTextSize.toPx()
|
||||
textAlign = android.graphics.Paint.Align.RIGHT
|
||||
}
|
||||
val minLabelHeight = (labelTextSize.toPx() * labelRatio.toFloat())
|
||||
val totalHeight = drawableArea.height
|
||||
val labelCount = max((drawableArea.height / minLabelHeight).roundToInt(), 2)
|
||||
|
||||
for (i in 0..labelCount) {
|
||||
val value = minValue + (i * ((maxValue - minValue) / labelCount))
|
||||
|
||||
val label = labelValueFormatter(value)
|
||||
val x = drawableArea.right - axisLineThickness.toPx() - (labelTextSize.toPx() / 2f)
|
||||
|
||||
labelPaint.getTextBounds(label, 0, label.length, textBounds)
|
||||
|
||||
val y =
|
||||
drawableArea.bottom - (i * (totalHeight / labelCount)) + (textBounds.height() / 2f)
|
||||
|
||||
canvas.nativeCanvas.drawText(label, x, y, labelPaint)
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.github.tehras.charts.bar.renderer.yaxis
|
||||
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Canvas
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
|
||||
interface YAxisDrawer {
|
||||
fun drawAxisLine(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
drawableArea: Rect
|
||||
)
|
||||
|
||||
fun drawAxisLabels(
|
||||
drawScope: DrawScope,
|
||||
canvas: Canvas,
|
||||
drawableArea: Rect,
|
||||
minValue: Float,
|
||||
maxValue: Float
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user