Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions COMPOSE_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# AndroidChart Compose Integration

## Overview

All chart classes from the `info.appdev.charting.charts` package have been successfully converted to Jetpack Compose composables. The implementation uses AndroidView wrappers to provide a Compose-friendly API while maintaining full compatibility with the existing chart rendering engine.

## Usage Examples

### Basic Line Chart

```kotlin
@Composable
fun MyLineChart() {
val entries = remember {
listOf(
Entry(0f, 10f),
Entry(1f, 20f),
Entry(2f, 15f),
Entry(3f, 30f)
)
}

val dataSet = LineDataSet(entries, "Sample Data").apply {
color = Color.BLUE
setDrawCircles(true)
}

val lineData = LineData(dataSet)

LineChart(
data = lineData,
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
description = "Sales Over Time",
animationDuration = 1000,
onValueSelected = { entry, highlight ->
println("Selected: ${entry?.y}")
}
)
}
```

### Bar Chart with Configuration

```kotlin
@Composable
fun MyBarChart() {
val barData = remember { createBarData() }

BarChart(
data = barData,
modifier = Modifier.fillMaxSize(),
description = "Monthly Revenue",
backgroundColor = Color(0xFFF5F5F5),
drawValueAboveBar = true,
animationDuration = 1500,
legend = { legend ->
legend.isEnabled = true
legend.textSize = 12f
},
xAxisConfig = { xAxis ->
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.setDrawGridLines(false)
},
leftAxisConfig = { axis ->
axis.axisMinimum = 0f
}
)
}
```

### Pie Chart with Customization

```kotlin
@Composable
fun MyPieChart() {
val pieData = remember { createPieData() }

PieChart(
data = pieData,
modifier = Modifier
.fillMaxWidth()
.height(400.dp),
drawHoleEnabled = true,
holeRadius = 40f,
transparentCircleRadius = 45f,
centerText = "Total Sales",
rotationEnabled = true,
usePercentValuesEnabled = true,
animationDuration = 1200,
legend = { legend ->
legend.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
legend.orientation = Legend.LegendOrientation.HORIZONTAL
}
)
}
```

### Combined Chart

```kotlin
@Composable
fun MyCombinedChart() {
val combinedData = remember {
CombinedData().apply {
setData(createLineData())
setData(createBarData())
}
}

CombinedChart(
data = combinedData,
modifier = Modifier.fillMaxSize(),
drawOrder = arrayOf(
CombinedChart.DrawOrder.BAR,
CombinedChart.DrawOrder.LINE
),
description = "Sales and Forecast",
animationDuration = 1000
)
}
```

### Stateful Chart with Updates

```kotlin
@Composable
fun InteractiveLineChart() {
val state = rememberLineChartState()
var selectedValue by remember { mutableStateOf<Float?>(null) }

Column {
LineChart(
data = state.data,
modifier = Modifier
.fillMaxWidth()
.height(300.dp),
state = state,
onValueSelected = { entry, _ ->
selectedValue = entry?.y
}
)

selectedValue?.let { value ->
Text("Selected: $value", modifier = Modifier.padding(16.dp))
}

Button(
onClick = {
state.data = generateNewData()
}
) {
Text("Refresh Data")
}
}
}
```

## Migration from View-Based Charts

### Before (View-Based)
```kotlin
AndroidView(factory = { context ->
LineChart(context).apply {
data = lineData
description.isEnabled = false
setTouchEnabled(true)
animateX(1000)
invalidate()
}
})
```

### After (Compose)
```kotlin
LineChart(
data = lineData,
description = null,
touchEnabled = true,
animationDuration = 1000
)
```

## Implementation Details

### AndroidView Wrapper Pattern
Each composable uses the `AndroidView` wrapper to embed the existing View-based chart implementation. This provides:
- Immediate compatibility with existing rendering code
- Full feature support without rewriting rendering logic
- Efficient integration with Compose's recomposition system

### Lifecycle Management
- `remember {}` - Creates chart instance once
- `DisposableEffect` - Cleans up chart resources on disposal
- `AndroidView.update {}` - Updates chart when parameters change

### Data Flow
1. User provides chart data as composable parameter
2. `update` lambda calls `chart.setData(data)`
3. Chart configuration applied (colors, animations, axes)
4. `chart.invalidate()` triggers redraw
5. Recomposition on parameter changes updates the chart
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,11 @@ abstract class BaseDataSet<T : Entry>() : IDataSet<T> {
mColors.add(value)
}

override val colors: MutableList<Int>
override var colors: MutableList<Int>
get() = mColors
set(value) {
mColors = value
}

override fun getColorByIndex(index: Int): Int {
return mColors[index % mColors.size]
Expand Down
118 changes: 118 additions & 0 deletions chartLibCompose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import info.git.versionHelper.getVersionText
import org.gradle.kotlin.dsl.implementation
import java.net.URI

plugins {
id("com.android.library")
id("maven-publish")
id("kotlin-android")
id("org.jetbrains.kotlin.plugin.compose") version "2.1.0"
id("com.vanniktech.maven.publish") version "0.34.0"
}

android {
namespace = "info.appdev.charting"
defaultConfig {
minSdk = 23
compileSdk = 36

// VERSION_NAME no longer available as of 4.1
// https://issuetracker.google.com/issues/158695880
buildConfigField("String", "VERSION_NAME", "\"${getVersionText()}\"")

consumerProguardFiles.add(File("proguard-lib.pro"))
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildTypes {
release {
isMinifyEnabled = false
}
}
buildFeatures {
buildConfig = true
compose = true
}
kotlin {
compilerOptions {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
}
}
testOptions {
unitTests.isReturnDefaultValues = true // this prevents "not mocked" error
}
}

dependencies {
implementation("androidx.annotation:annotation:1.9.1")
implementation("androidx.core:core:1.17.0")
implementation("androidx.activity:activity-ktx:1.12.2")
implementation("com.github.AppDevNext.Logcat:LogcatCoreLib:3.4")
api(project(":chartLib"))

// Compose dependencies
val composeBom = platform("androidx.compose:compose-bom:2024.12.01")
implementation(composeBom)
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.runtime:runtime")
implementation("androidx.compose.runtime:runtime-saveable")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")

testImplementation("junit:junit:4.13.2")
}

tasks.register<Jar>("androidSourcesJar") {
archiveClassifier.set("sources")
from(android.sourceSets["main"].java.srcDirs)
}

group = "info.mxtracks"
var versionVersion = getVersionText()
println("Build version $versionVersion")

mavenPublishing {
pom {
name = "Android Chart"
description =
"A powerful Android chart view/graph view library, supporting line- bar- pie- radar- bubble- and candlestick charts as well as scaling, dragging and animations"
inceptionYear = "2022"
url = "https://github.com/AppDevNext/AndroidChart/"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution = "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "AppDevNext"
name = "AppDevNext"
url = "https://github.com/AppDevNext/"
}
}
scm {
url = "https://github.com/AppDevNext/AndroidChart/"
connection = "scm:git:git://github.com/AppDevNext/AndroidChart.git"
developerConnection = "scm:git:ssh://git@github.com/AppDevNext/AndroidChart.git"
}
}

// Github packages
repositories {
maven {
version = "$versionVersion-SNAPSHOT"
name = "GitHubPackages"
url = URI("https://maven.pkg.github.com/AppDevNext/AndroidChart")
credentials {
username = System.getenv("GITHUBACTOR")
password = System.getenv("GITHUBTOKEN")
}
}
}
}
Binary file added chartLibCompose/ic_launcher-web.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions chartLibCompose/proguard-lib.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Whitelist AndroidChart
# Preserve all public classes and methods

-keep class info.appdev.charting.** { *; }
-keep public class info.appdev.charting.animation.* {
public protected *;
}
6 changes: 6 additions & 0 deletions chartLibCompose/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>

<application />

</manifest>
Loading
Loading