Skip to content

parrotcar00/vico

 
 

Repository files navigation

These charts are implemented in the sample app.

Vico

Vico is a light and extensible chart library for Jetpack Compose and the view system. It comprises two main modules:

  • compose (for Jetpack Compose)
  • view (for views)

Vico has a very low number of dependencies, and these two modules don’t depend on each other. Find out how.

A foreword by the founder

As a library compatible with both Compose and views, Vico is quite unique. It doesn’t depend on the interoperability between the two UI systems.

The shared, main logic resides in the core module and depends on the Android SDK. It doesn’t know anything about views or Jetpack Compose. Likewise, view (for views) doesn’t know anything about Jetpack Compose, and compose (for Jetpack Compose) doesn’t know anything about views.

Achieving module independence

I was a little curious about Jetpack Compose’s internals and how come it is interoperable with views.

“Can you, fairly easily, share the code used to draw on the Canvas between these two UI paradigms?” I asked myself.

The answer is yes. core uses android.graphics.Canvas (also used by views) to draw charts, and androidx.compose.ui.graphics.drawscope.DrawScope (used by Jetpack Compose) exposes android.graphics.Canvas via DrawScope#canvas#nativeCanvas. It’s similar for other APIs, like Path.

This approach encourages a greater level of abstraction and promotes separation of concerns. It also helped make the API highly extensible.

Getting started

  1. Ensure your app’s minimum SDK version is 16 (for core and view) or 21 (for compose, compose-m2, and compose-m3). This is declared in the module-level build.gradle file.

    android {
        defaultConfig {
            minSdk 16 // Or 21 for Jetpack Compose.
            ...
        }
        ...
    }
  2. Ensure the mavenCentral() repository is declared in the project-level build.gradle file:

    allprojects {
        repositories {
            mavenCentral()
            ...
        }
        ...
    }
  3. Declare the dependencies you need in the module-level build.gradle file. All modules depend on vico.core, so you don’t need to add it as a dependency.

    dependencies {
    
        // Provides the utilities needed to use Vico in the view system.
        implementation "com.patrykandpatryk.vico:view:1.5.0"
    
        // Provides the utilities needed to use Vico in Jetpack Compose.
        implementation "com.patrykandpatryk.vico:compose:1.5.0"
    
        // An optional addition for `vico.compose` that creates a `ChartStyle` based on an M2 Material Theme.
        implementation "com.patrykandpatryk.vico:compose-m2:1.5.0"
    
        // An optional addition for `vico.compose` that creates a `ChartStyle` based on an M3 Material Theme.
        implementation "com.patrykandpatryk.vico:compose-m3:1.5.0"
    
        ...
    }

Modules

The following table outlines the modules included in this library:

Artifact Description
core Includes the core logic for charts and other components. All modules depend on core.
view Provides the utilities needed to use Vico in the view system.
compose Provides the utilities needed to use Vico in Jetpack Compose.
compose-m2 An optional addition for compose that creates a ChartStyle based on an M2 Material Theme.
compose-m3 An optional addition for compose that creates a ChartStyle based on an M3 Material Theme.

Sample app

Included in this repository is a sample app with multiple charts and two tabs—one for Jetpack Compose, and the other one for the view system. Studying the source code of the app will give you a deep understanding of how to use Vico, including topics such as updating data and customizing charts. All of the charts included in the graphic at the top of this README are implemented in the sample app.

Basic example

Chart data in Vico is stored in ChartEntryModels. For a static chart, you can create a ChartEntryModel instance via the entryModelOf helper function:

val entryModel = entryModelOf(5f, 15f, 10f, 20f, 10f)

This creates a ChartEntryModel that can be used in, for example, a column chart. The chart will have five columns.

In Jetpack Compose, use the Chart composable:

Chart(
    chart = columnChart(),
    model = entryModel,
    startAxis = startAxis(),
    bottomAxis = bottomAxis(),
)

In the view system, use ChartView:

<com.patrykandpatryk.vico.view.chart.ChartView
    android:id="@+id/chart"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:chart="column"
    app:showBottomAxis="true"
    app:showStartAxis="true" />
findViewById<ChartView>(R.id.chart).model = entryModel

Dynamic data & data updates

For dynamic data sets, use ChartEntryModelProducer (or ComposedChartEntryModelProducer for composed charts).

For this example, we’ll use a function that generates a random list of FloatEntry instances. A FloatEntry describes a single chart entry (e.g., a column).

fun getRandomEntries() = List(size = 5) {
    25f * Random.nextFloat()
}.mapIndexed { x, y ->
    FloatEntry(
        x = x.toFloat(),
        y = y,
    )
}

A list returned by this function can be used to initialize a ChartEntryModelProducer, which should happen in the viewmodel:

val producer = ChartEntryModelProducer(getRandomEntries())

In Compose, you can once again use the Chart composable, but this time the overload with a chartModelProducer parameter:

Chart(
    chart = lineChart(),
    chartModelProducer = producer,
    startAxis = startAxis(),
    bottomAxis = bottomAxis(),
)

In the view system, you can connect a chart to a ChartEntryModelProducer as follows:

<com.patrykandpatryk.vico.view.chart.ChartView
    android:id="@+id/chart"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:chartType="column"
    app:showBottomAxis="true"
    app:showStartAxis="true" />
findViewById<ChartView>(R.id.chart).entryProducer = producer

With ChartEntryModelProducer, you can update the data displayed by a chart. For the above example, this would be done as follows:

chartModelProducer.setEntries(getRandomEntries())

Differences are animated by default.

Composed charts

You can combine multiple charts into one. This example uses the getRandomEntries function from above.

A composed chart requires a ComposedChartEntryModel. In the case of static charts, you can directly create a ComposedChartEntryModel instance via the composedChartEntryModelOf helper function. You can also use the + operator to create a ComposedChartEntryModel out of two ChartEntryModels. For dynamic composed charts, use ComposedChartEntryModelProducer.

For this example, we’ll use a ComposedChartEntryModelProducer. You can create a ComposedChartEntryModelProducer out of two regular ChartEntryModelProducers:

val firstProducer = ChartEntryModelProducer(getRandomEntries())
val secondProducer = ChartEntryModelProducer(getRandomEntries())
val composedProducer = firstProducer + secondProducer

A composed chart can be created in Jetpack Compose as follows:

Chart(
    chart = lineChart() + columnChart(),
    chartModelProducer = composedProducer,
    startAxis = startAxis(),
    bottomAxis = bottomAxis(),
)

And here’s the same chart in the view system. Note that we’re now using ComposedChartView:

<com.patrykandpatryk.vico.view.chart.ComposedChartView
    android:id="@+id/chart"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:chartType="column"
    app:showBottomAxis="true"
    app:showStartAxis="true"
    app:charts="line|column" />
findViewById<ComposedChartView>(R.id.chart).entryProducer = composedProducer

Further reading

Vico offers rich options for customization and an extensible API. The following resources are available to help you learn about it:

  • The sample app contains a full implementation of Vico.
  • The wiki describes core topics and includes a detailed customization guide.
  • The API reference describes every public class, function, and field.

About

A light and extensible chart library for Android.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Kotlin 99.9%
  • CSS 0.1%