Effortlessly create GitHub-style heatmaps in Jetpack Compose—perfect for visualizing a variety of time-based data patterns.
Platform | Default Style | Custom Style |
---|---|---|
Android | ||
Desktop | ||
WasmJs |
This project is based on kotlinx-datetime
for LocalDate-related operations, not java.time.*
!
refer to kotlinx-datetime to add dep.
build.gradle.kts
implementation("com.fleeys:heatmap:1.0.5")
build.gradle
implementation 'com.fleeys:heatmap:1.0.5'
// ../library/src/commonMain/kotlin/com/fleeys/heatmap/HeatMap.kt
@Composable
fun <T> HeatMap(
modifier: Modifier = Modifier,
data: List<Heat<T>>,
style: HeatMapStyle = HeatMapStyle(),
scrollState: LazyListState = rememberLazyListState(),
onScrolledToTop: (() -> Unit)? = null,
onScrolledToBottom: (() -> Unit)? = null,
onHeatClick: (Heat<T>) -> Unit,
)
Important
The project is in the experimental phase. All APIs can change incompatibly or be dropped without the deprecation cycle!
Works right out of the box without much setup.
// ../sample/src/commonMain/com/fleeys/heatmap/sample/SampleHeatMap.kt
@Composable
fun SampleHeatMap() {
val scrollState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
var heatMapStyle by remember { mutableStateOf<HeatMapStyle?>(null) }
val toggleStyle = { heatMapStyle = if (heatMapStyle == null) CustomHeatMapStyle else null }
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
.padding(16.dp)
) {
HeatMap(
data = generateHeats(),
scrollState = scrollState,
style = heatMapStyle ?: HeatMapStyle(),
onScrolledToTop = { println("Scrolled to Top") },
onScrolledToBottom = { println("Scrolled to Bottom") }
) { println("Clicked: $it") }
Column(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
onClick = toggleStyle,
) {
Text("Toggle Style")
}
Button(onClick = {
coroutineScope.launch {
scrollState.animateScrollToItem(0)
}
}) {
Text("Scroll to Top")
}
Button(onClick = {
coroutineScope.launch {
scrollState.animateScrollToItem(scrollState.layoutInfo.totalItemsCount - 1)
}
}) {
Text("Scroll to Bottom")
}
}
}
}
// fake data
private fun generateHeats(): List<Heat<Unit>> {
val startDate = LocalDate(2022, 11, 11)
val curDate = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
return generateSequence(startDate) { date ->
if (date < curDate) date DatePeriod(days = 1) else null
}.map { date ->
val value = Random.nextDouble(0.0, 32.0)
Heat<Unit>(date, value)
}.toList()
}
Almost everything you see can be manipulated.
// ../library/src/commonMain/kotlin/com/fleeys/heatmap/style/HeatMapStyle.kt
@Immutable
data class HeatMapStyle(
val heatStyle: HeatStyle = HeatStyle(),
val labelStyle: LabelStyle = LabelStyle(),
val heatMapPadding: PaddingValues = PaddingValues(0.dp),
val startFromEnd: Boolean = true
)
// Sample Custom Style
// ../sample/src/commonMain/kotlin/com/fleeys/heatmap/sample/CustomHeatMapStyle.kt
internal val CustomHeatMapStyle = HeatMapStyle().copy(
heatStyle = HeatStyle().copy(
heatColor = HeatColor().copy(
activeLowestColor = Color(0xff212f57),
activeHighestColor = Color(0xff456de3),
),
heatShape = CircleShape,
),
startFromEnd = false
)
Not just present, but interact.
- Click
- Scroll
- Reaching the top or pulling back at the end
The operation is richer.
// ../library/src/commonMain/kotlin/com/fleeys/heatmap/HeatMap.kt
import kotlinx.datetime.LocalDate
data class Heat<T>(
val date: LocalDate,
var value: Double,
var data: T? = null
)
This project is built on Compose in an attempt to adapt to the Compose Multiplatform.
The currently adapted platforms are listed below:
Platform | State | Sample | Note |
---|---|---|---|
Android | ✅ | Android-Sample | |
Desktop | ✅ | Desktop-Sample | |
WasmJs | 😑 | ... | (1) |
- Unfortunately, due to the fact that I don't know much about it, the realization is less than ideal. If you can help me refine it, quite welcome to contribute!
Feel free to submit an issue if you have any feedback or suggestions!
The project is quite happy to receive your contributions, and it will be much more robust with your help!
I hope you like it, and if you think it's good, feel free to give a ⭐ !
Copyright (c) 2024-present. Fleey
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.