Skip to content

Commit 9bb7a40

Browse files
committed
All usable in compose
1 parent af2c75a commit 9bb7a40

19 files changed

+2156
-1
lines changed

COMPOSE_MIGRATION.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# AndroidChart Compose Integration
2+
3+
## Overview
4+
5+
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.
6+
7+
## Usage Examples
8+
9+
### Basic Line Chart
10+
11+
```kotlin
12+
@Composable
13+
fun MyLineChart() {
14+
val entries = remember {
15+
listOf(
16+
Entry(0f, 10f),
17+
Entry(1f, 20f),
18+
Entry(2f, 15f),
19+
Entry(3f, 30f)
20+
)
21+
}
22+
23+
val dataSet = LineDataSet(entries, "Sample Data").apply {
24+
color = Color.BLUE
25+
setDrawCircles(true)
26+
}
27+
28+
val lineData = LineData(dataSet)
29+
30+
LineChart(
31+
data = lineData,
32+
modifier = Modifier
33+
.fillMaxWidth()
34+
.height(300.dp),
35+
description = "Sales Over Time",
36+
animationDuration = 1000,
37+
onValueSelected = { entry, highlight ->
38+
println("Selected: ${entry?.y}")
39+
}
40+
)
41+
}
42+
```
43+
44+
### Bar Chart with Configuration
45+
46+
```kotlin
47+
@Composable
48+
fun MyBarChart() {
49+
val barData = remember { createBarData() }
50+
51+
BarChart(
52+
data = barData,
53+
modifier = Modifier.fillMaxSize(),
54+
description = "Monthly Revenue",
55+
backgroundColor = Color(0xFFF5F5F5),
56+
drawValueAboveBar = true,
57+
animationDuration = 1500,
58+
legend = { legend ->
59+
legend.isEnabled = true
60+
legend.textSize = 12f
61+
},
62+
xAxisConfig = { xAxis ->
63+
xAxis.position = XAxis.XAxisPosition.BOTTOM
64+
xAxis.setDrawGridLines(false)
65+
},
66+
leftAxisConfig = { axis ->
67+
axis.axisMinimum = 0f
68+
}
69+
)
70+
}
71+
```
72+
73+
### Pie Chart with Customization
74+
75+
```kotlin
76+
@Composable
77+
fun MyPieChart() {
78+
val pieData = remember { createPieData() }
79+
80+
PieChart(
81+
data = pieData,
82+
modifier = Modifier
83+
.fillMaxWidth()
84+
.height(400.dp),
85+
drawHoleEnabled = true,
86+
holeRadius = 40f,
87+
transparentCircleRadius = 45f,
88+
centerText = "Total Sales",
89+
rotationEnabled = true,
90+
usePercentValuesEnabled = true,
91+
animationDuration = 1200,
92+
legend = { legend ->
93+
legend.verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
94+
legend.orientation = Legend.LegendOrientation.HORIZONTAL
95+
}
96+
)
97+
}
98+
```
99+
100+
### Combined Chart
101+
102+
```kotlin
103+
@Composable
104+
fun MyCombinedChart() {
105+
val combinedData = remember {
106+
CombinedData().apply {
107+
setData(createLineData())
108+
setData(createBarData())
109+
}
110+
}
111+
112+
CombinedChart(
113+
data = combinedData,
114+
modifier = Modifier.fillMaxSize(),
115+
drawOrder = arrayOf(
116+
CombinedChart.DrawOrder.BAR,
117+
CombinedChart.DrawOrder.LINE
118+
),
119+
description = "Sales and Forecast",
120+
animationDuration = 1000
121+
)
122+
}
123+
```
124+
125+
### Stateful Chart with Updates
126+
127+
```kotlin
128+
@Composable
129+
fun InteractiveLineChart() {
130+
val state = rememberLineChartState()
131+
var selectedValue by remember { mutableStateOf<Float?>(null) }
132+
133+
Column {
134+
LineChart(
135+
data = state.data,
136+
modifier = Modifier
137+
.fillMaxWidth()
138+
.height(300.dp),
139+
state = state,
140+
onValueSelected = { entry, _ ->
141+
selectedValue = entry?.y
142+
}
143+
)
144+
145+
selectedValue?.let { value ->
146+
Text("Selected: $value", modifier = Modifier.padding(16.dp))
147+
}
148+
149+
Button(
150+
onClick = {
151+
state.data = generateNewData()
152+
}
153+
) {
154+
Text("Refresh Data")
155+
}
156+
}
157+
}
158+
```
159+
160+
## Migration from View-Based Charts
161+
162+
### Before (View-Based)
163+
```kotlin
164+
AndroidView(factory = { context ->
165+
LineChart(context).apply {
166+
data = lineData
167+
description.isEnabled = false
168+
setTouchEnabled(true)
169+
animateX(1000)
170+
invalidate()
171+
}
172+
})
173+
```
174+
175+
### After (Compose)
176+
```kotlin
177+
LineChart(
178+
data = lineData,
179+
description = null,
180+
touchEnabled = true,
181+
animationDuration = 1000
182+
)
183+
```
184+
185+
## Implementation Details
186+
187+
### AndroidView Wrapper Pattern
188+
Each composable uses the `AndroidView` wrapper to embed the existing View-based chart implementation. This provides:
189+
- Immediate compatibility with existing rendering code
190+
- Full feature support without rewriting rendering logic
191+
- Efficient integration with Compose's recomposition system
192+
193+
### Lifecycle Management
194+
- `remember {}` - Creates chart instance once
195+
- `DisposableEffect` - Cleans up chart resources on disposal
196+
- `AndroidView.update {}` - Updates chart when parameters change
197+
198+
### Data Flow
199+
1. User provides chart data as composable parameter
200+
2. `update` lambda calls `chart.setData(data)`
201+
3. Chart configuration applied (colors, animations, axes)
202+
4. `chart.invalidate()` triggers redraw
203+
5. Recomposition on parameter changes updates the chart

chartLib/src/main/kotlin/info/appdev/charting/data/BaseDataSet.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,11 @@ abstract class BaseDataSet<T : Entry>() : IDataSet<T> {
126126
mColors.add(value)
127127
}
128128

129-
override val colors: MutableList<Int>
129+
override var colors: MutableList<Int>
130130
get() = mColors
131+
set(value) {
132+
mColors = value
133+
}
131134

132135
override fun getColorByIndex(index: Int): Int {
133136
return mColors[index % mColors.size]

chartLibCompose/build.gradle.kts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import info.git.versionHelper.getVersionText
2+
import org.gradle.kotlin.dsl.implementation
3+
import java.net.URI
4+
5+
plugins {
6+
id("com.android.library")
7+
id("maven-publish")
8+
id("kotlin-android")
9+
id("org.jetbrains.kotlin.plugin.compose") version "2.1.0"
10+
id("com.vanniktech.maven.publish") version "0.34.0"
11+
}
12+
13+
android {
14+
namespace = "info.appdev.charting"
15+
defaultConfig {
16+
minSdk = 23
17+
compileSdk = 36
18+
19+
// VERSION_NAME no longer available as of 4.1
20+
// https://issuetracker.google.com/issues/158695880
21+
buildConfigField("String", "VERSION_NAME", "\"${getVersionText()}\"")
22+
23+
consumerProguardFiles.add(File("proguard-lib.pro"))
24+
}
25+
compileOptions {
26+
sourceCompatibility = JavaVersion.VERSION_17
27+
targetCompatibility = JavaVersion.VERSION_17
28+
}
29+
buildTypes {
30+
release {
31+
isMinifyEnabled = false
32+
}
33+
}
34+
buildFeatures {
35+
buildConfig = true
36+
compose = true
37+
}
38+
kotlin {
39+
compilerOptions {
40+
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17)
41+
}
42+
}
43+
testOptions {
44+
unitTests.isReturnDefaultValues = true // this prevents "not mocked" error
45+
}
46+
}
47+
48+
dependencies {
49+
implementation("androidx.annotation:annotation:1.9.1")
50+
implementation("androidx.core:core:1.17.0")
51+
implementation("androidx.activity:activity-ktx:1.12.2")
52+
implementation("com.github.AppDevNext.Logcat:LogcatCoreLib:3.4")
53+
api(project(":chartLib"))
54+
55+
// Compose dependencies
56+
val composeBom = platform("androidx.compose:compose-bom:2024.12.01")
57+
implementation(composeBom)
58+
implementation("androidx.compose.material3:material3")
59+
implementation("androidx.compose.ui:ui")
60+
implementation("androidx.compose.ui:ui-graphics")
61+
implementation("androidx.compose.foundation:foundation")
62+
implementation("androidx.compose.runtime:runtime")
63+
implementation("androidx.compose.runtime:runtime-saveable")
64+
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.7")
65+
66+
testImplementation("junit:junit:4.13.2")
67+
}
68+
69+
tasks.register<Jar>("androidSourcesJar") {
70+
archiveClassifier.set("sources")
71+
from(android.sourceSets["main"].java.srcDirs)
72+
}
73+
74+
group = "info.mxtracks"
75+
var versionVersion = getVersionText()
76+
println("Build version $versionVersion")
77+
78+
mavenPublishing {
79+
pom {
80+
name = "Android Chart"
81+
description =
82+
"A powerful Android chart view/graph view library, supporting line- bar- pie- radar- bubble- and candlestick charts as well as scaling, dragging and animations"
83+
inceptionYear = "2022"
84+
url = "https://github.com/AppDevNext/AndroidChart/"
85+
licenses {
86+
license {
87+
name = "The Apache License, Version 2.0"
88+
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
89+
distribution = "http://www.apache.org/licenses/LICENSE-2.0.txt"
90+
}
91+
}
92+
developers {
93+
developer {
94+
id = "AppDevNext"
95+
name = "AppDevNext"
96+
url = "https://github.com/AppDevNext/"
97+
}
98+
}
99+
scm {
100+
url = "https://github.com/AppDevNext/AndroidChart/"
101+
connection = "scm:git:git://github.com/AppDevNext/AndroidChart.git"
102+
developerConnection = "scm:git:ssh://git@github.com/AppDevNext/AndroidChart.git"
103+
}
104+
}
105+
106+
// Github packages
107+
repositories {
108+
maven {
109+
version = "$versionVersion-SNAPSHOT"
110+
name = "GitHubPackages"
111+
url = URI("https://maven.pkg.github.com/AppDevNext/AndroidChart")
112+
credentials {
113+
username = System.getenv("GITHUBACTOR")
114+
password = System.getenv("GITHUBTOKEN")
115+
}
116+
}
117+
}
118+
}
3.96 KB
Loading

chartLibCompose/proguard-lib.pro

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Whitelist AndroidChart
2+
# Preserve all public classes and methods
3+
4+
-keep class info.appdev.charting.** { *; }
5+
-keep public class info.appdev.charting.animation.* {
6+
public protected *;
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest>
3+
4+
<application />
5+
6+
</manifest>

0 commit comments

Comments
 (0)