Skip to content

Instantly share code, notes, and snippets.

@logickoder
Created September 29, 2024 16:44
Show Gist options
  • Save logickoder/922b2d0e942f9e5731ef56be0c3cb598 to your computer and use it in GitHub Desktop.
Save logickoder/922b2d0e942f9e5731ef56be0c3cb598 to your computer and use it in GitHub Desktop.
Compose Hour Bar Chart
package dev.logickoder.compose.chart
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun ChartView(
barHeight: Dp,
modifier: Modifier = Modifier,
) {
val list = remember {
buildList {
add(OneHour)
repeat(5) {
add((0..TwentyFourHours).random().toLong())
}
add(TwentyFourHours)
}
}
val blockWidthDp = 19.dp
val textWidth = 30.dp
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(19.dp),
content = {
Canvas(
modifier = Modifier
.height(barHeight)
.fillMaxWidth()
.background(Color.Green),
onDraw = {
// Draw the horizontal lines
val lines = 4
var space = size.height / (lines - 1)
var startY = 0f
repeat(lines) {
drawLine(
color = Color.Yellow,
start = Offset(0f, startY),
end = Offset(size.width, startY),
strokeWidth = 1.dp.toPx()
)
startY += space
}
// Draw the bars
val blockWidth = blockWidthDp.toPx()
val minWidth = minOf(blockWidthDp, textWidth).toPx()
val maxWidth = maxOf(blockWidthDp, textWidth).toPx()
space = (size.width - (maxWidth * list.size)) / (list.size - 1)
var startX = 0f
for (i in list.indices) {
val hour = list[i]
val height = (hour / TwentyFourHours.toFloat()) * size.height
val trimWidth = maxWidth - minWidth
drawRect(
color = Color.Red,
topLeft = Offset(startX + trimWidth / 2, size.height - height),
size = Size(blockWidth, height)
)
startX += maxWidth + space
}
}
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
content = {
Days.forEach { day ->
Box(
modifier = Modifier
.size(textWidth)
.background(Color.Yellow, shape = CircleShape),
contentAlignment = Alignment.Center,
content = {
Text(text = day, fontSize = 15.sp, color = Color.Black)
}
)
}
}
)
}
)
}
private const val OneHour = 1_000L * 60 * 60 // 1hr in millis
private const val TwentyFourHours = OneHour * 24
private val Days = listOf("M", "T", "W", "T", "F", "S", "S")
@Preview(showBackground = true)
@Composable
private fun ChartViewPreview() {
ChartView(200.dp)
}
@logickoder
Copy link
Author

Preview

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment