Skip to content

About

Beautiful, animated, fully customizable charts for Jetpack Compose.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Compose Charts logo

Compose Charts

Beautiful, animated, fully customizable charts for Jetpack Compose.

Drop-in chart cards that look great by default, and a styling API that lets you change every colour, size and spacing.

Kotlin Jetpack Compose Min SDK Maven Central License Docs

Website and documentation →


Preview

Vertical bar Area range and line Donut
Animated vertical bar chart Animated area range and line chart Animated donut chart
Two series compared above and below a shared baseline. A smooth line inside a soft ribbon that can run in any direction. Rounded segments filling a gauge, with the percentage counting up in the centre.
Doughnut Spline area Stacked bar
Animated doughnut chart Animated spline area chart Animated stacked bar chart
Segments that thicken one after another around a shaded hole. A thick smoothed line over a fading fill, edge to edge. Rounded stacks of several series, with a trend label in the corner.
Horizontal bar Ranked bar Overlapping area
Animated horizontal bar chart Animated ranked bar chart Animated overlapping area chart
Pill-shaped progress bars under a profile row. A labelled staircase of bars, longest first, from navy to sky. Two translucent years laid over each other under a coloured header.
Mirrored area Stacked column Floating bar
Animated mirrored area chart Animated stacked column chart Animated floating bar chart
Smooth layered waves above and below a baseline, with a row of zone swatches. Two series side by side in each column, with month tabs and a profile footer. Bars spanning a low to a high value over a dashed grid, with time range chips.
Heatmap
Animated heatmap chart
A contribution grid shaded by activity, with year tabs and a Less to More legend.

Documentation

The full docs live at nameisjayant.github.io/Compose-Charts: a getting started guide, plus a page for every chart with a live preview, copyable code for the data, the chart card and the bare chart, and notes on how it behaves.

Features

  • 📊 Ready-made chart cards: title, subtitle, legend and an action slot, all built in.
  • 🎨 Every visual is configurable through immutable XxxStyle classes built with XxxDefaults.style(...).
  • ✨ Animated by default: values animate on first draw and whenever the data changes. Pass animationSpec = null to turn it off.
  • 🧩 Use the parts you need: use a full XxxChartCard, or put the bare chart composable inside your own layout.
  • 🪶 Light dependencies: only Compose UI, Foundation and Coroutines. No Hilt, Material or navigation library is forced on your app.
  • 🔒 Explicit API mode, so the public API is exactly what is meant to be public.

Charts

Chart Composables Highlights
Vertical bar VerticalBarChart, VerticalBarChartCard One or two series (up and down from a baseline), pill-shaped bars, grid lines
Area range and line AreaRangeLineChart, AreaRangeLineChartCard Smoothed line, fading ribbon, data points, axis ranges and label formatters
Donut DonutChart, DonutChartCard Rounded overlapping segments on a track, animated percentage in the centre, side legend and a summary row
Doughnut DoughnutChart, DoughnutChartCard Segments that get thicker one after another, a shaded hole, a tinted header and a footer slot
Spline area SplineAreaChart, SplineAreaChartCard A thick smoothed line over a fading fill, edge to edge, under a headline value, change badge and action tile
Stacked bar StackedBarChart, StackedBarChartCard Any number of series stacked per bar, rounded stack ends, a title icon, a description and a trend label
Horizontal bar HorizontalBarChart, HorizontalBarChartCard Pill-shaped fills over lighter tracks, a profile row with avatar and action button, and a clipped description
Ranked bar RankedBarChart, RankedBarChartCard Flush bars sorted longest first in a shaded palette, labels inside each bar in a contrasting colour, a list header and a footer note
Overlapping area OverlappingAreaChart, OverlappingAreaChartCard Translucent straight-edged areas laid over each other, a coloured header, filter chips, a legend, a profile row and a footer note
Mirrored area MirroredAreaChart, MirroredAreaChartCard Smooth translucent layers growing up and down from a shared baseline, a dated header, overlapping zone swatches and a summary value
Stacked column StackedColumnChart, StackedColumnChartCard Flush side-by-side stripes per column, a glowing sparkline, selectable tabs, a legend and a tinted profile footer
Floating bar FloatingBarChart, FloatingBarChartCard Pill-shaped bars from a low to a high value, each in its own colour, dashed grid lines with 8k-style labels, a caption and time range chips
Heatmap HeatmapChart, HeatmapChartCard, HeatmapLegend Rounded cells shaded into levels by value, column labels, outlined year tabs, a Less to More legend and a full-width footer button

More charts are on the way.

Installation

Compose Charts is published on Maven Central. No extra repository is needed, just make sure mavenCentral() is listed (new Android projects include it by default):

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

Then add the dependency:

// app/build.gradle.kts
dependencies {
    implementation("io.github.nameisjayant:compose-charts:0.1.0")
}
Version catalog
[versions]
composeCharts = "0.1.0"

[libraries]
compose-charts = { group = "io.github.nameisjayant", name = "compose-charts", version.ref = "composeCharts" }

Usage

Every chart comes in two versions:

  • XxxChartCard: the chart inside a ready-made card, with a title, subtitle, legend and action slot.
  • XxxChart: the bare chart, with no card frame, to put inside your own layout. Give it a size with modifier.

Vertical bar

val upperSeries = BarSeries(
    label = "Data one",
    values = listOf(90f, 24f, 63f, 39f, 46f, 49f, 61f),
    color = VerticalBarChartDefaults.UpperBarColor,
)
val lowerSeries = BarSeries(
    label = "Data two",
    values = listOf(14f, 32f, 20f, 28f, 45f, 32f, 28f),
    color = VerticalBarChartDefaults.LowerBarColor,
)

Chart card

VerticalBarChartCard(
    title = "Vertical bar",
    subtitle = "Statistics of the month",
    upperSeries = upperSeries,
    lowerSeries = lowerSeries,
    chartStyle = VerticalBarChartDefaults.style(barWidth = 24.dp),
)

Chart only

VerticalBarChart(
    upperSeries = upperSeries,
    lowerSeries = lowerSeries,
    modifier = Modifier.fillMaxWidth().height(160.dp),
    style = VerticalBarChartDefaults.style(barWidth = 24.dp),
)

Area range and line

val series = AreaRangeLineSeries(
    label = "Temperature",
    points = listOf(
        LinePoint(x = -77f, y = 75f),
        LinePoint(x = -39f, y = 53f),
        LinePoint(x = -66f, y = 24f),
        LinePoint(x = -40f, y = 14f),
        LinePoint(x = -17f, y = 5f),
    ),
    lineColor = AreaRangeLineChartDefaults.LineColor,
    bandColor = AreaRangeLineChartDefaults.BandColor,
    pointColor = AreaRangeLineChartDefaults.PointColor,
)

Chart card

AreaRangeLineChartCard(
    title = "Temperatures",
    subtitle = "Average temperatures for July",
    series = series,
    xRange = AxisRange(min = -80f, max = -10f, step = 10f),
    yRange = AxisRange(min = 0f, max = 75f, step = 25f),
    yLabelFormatter = { "${it.roundToInt()} km" },
)

Chart only

AreaRangeLineChart(
    series = series,
    modifier = Modifier.fillMaxWidth().height(220.dp),
    xRange = AxisRange(min = -80f, max = -10f, step = 10f),
    yRange = AxisRange(min = 0f, max = 75f, step = 25f),
    yLabelFormatter = { "${it.roundToInt()} km" },
)

Points are joined in list order, so the line can run top to bottom, as in the altitude profile above. If you leave out xRange or yRange, a range with round step values is picked for you.

Donut

val segments = listOf(
    DonutSegment("Documents", 22f, DonutChartDefaults.DocumentsColor),
    DonutSegment("Photos", 47f, DonutChartDefaults.PhotosColor),
    DonutSegment("Music", 38f, DonutChartDefaults.MusicColor),
    DonutSegment("Videos", 30f, DonutChartDefaults.VideosColor),
)

Chart card

DonutChartCard(
    title = "Storage of your device",
    segments = segments,
    maxValue = 178f,
    caption = "Used storage",
    value = "137GB",
    action = { ChartSettingsIcon() },
)

Chart only

DonutChart(
    segments = segments,
    modifier = Modifier.size(160.dp),
    maxValue = 178f,
)

With maxValue the ring works as a gauge: the segments fill 137 of 178, and the centre shows 77%. Leave it out and the segments share the whole ring. Use centerLabelFormatter to change the centre text, and DonutChartDefaults.style(startAngle = -90f) to start at 12 o'clock.

Doughnut

val segments = listOf(
    DonutSegment("css", 11f, DoughnutChartDefaults.CssColor),
    DonutSegment("html", 12f, DoughnutChartDefaults.HtmlColor),
    DonutSegment("sass", 50f, DoughnutChartDefaults.SassColor),
)

Chart card

DoughnutChartCard(
    title = "Doughnut",
    subtitle = "Browser market shares at a specific website, 2014",
    segments = segments,
    maxValue = 100f,
    footer = { /* e.g. an avatar, a name and a profile button */ },
)

Chart only

DoughnutChart(
    segments = segments,
    modifier = Modifier.size(200.dp),
    maxValue = 100f,
)

Each segment is a little thicker than the one before, and the last one reaches the edge. The segments run clockwise and finish at 12 o'clock, so the empty track sits just before it, and the centre shows the filled share (73%). Use DoughnutChartDefaults.style(endAngle = ..., firstSegmentRadiusFraction = ..., holeRadiusFraction = ...) to move the end point, change how much the segments thicken, or resize the hole.

Spline area

val trend = listOf(180f, 148f, 194f, 184f, 255f, 120f, 200f, 248f, 194f, 200f, 140f, 196f, 192f, 248f)

Chart card

SplineAreaChartCard(
    title = "Expected earnings",
    value = "€682.5",
    badge = "+2.45%",
    values = trend,
    action = { ChartBarsIcon(color = SplineAreaChartCardDefaults.ActionIconColor) },
)

Chart only

SplineAreaChart(
    values = trend,
    modifier = Modifier.fillMaxWidth().height(170.dp),
)

The values are spread evenly from the left edge to the right edge, and in the card the chart reaches the card's left, right and bottom edges. By default the line is scaled to the data's own range, with the lowest value 45% of the way up so the fill has room to fade. Pass minValue = 0f and SplineAreaChartDefaults.style(bottomSpaceFraction = 0f) to measure from zero instead.

Stacked bar

val series = listOf(
    BarSeries("Store", listOf(70f, 40f, 22f, 40f, 17f, 21f, 13f, 8f), StackedBarChartDefaults.BottomColor),
    BarSeries("Web", listOf(30f, 62f, 55f, 28f, 15f, 19f, 10f, 6f), StackedBarChartDefaults.MiddleColor),
    BarSeries("App", listOf(30f, 18f, 29f, 15f, 30f, 10f, 17f, 40f), StackedBarChartDefaults.TopColor),
)

Chart card

StackedBarChartCard(
    title = "Bar chart",
    subtitle = "Orders per day, split by channel: store, website and mobile app.",
    trend = "+86%",
    series = series,
)

Chart only

StackedBarChart(
    series = series,
    modifier = Modifier.fillMaxWidth().height(130.dp),
)

The first series sits at the bottom of every stack. Only the top and bottom of each whole stack are rounded; the segments inside meet flush. The bars share the width left after barSpacing, so they get wider when there are fewer of them. Cap them with StackedBarChartDefaults.style(maxBarWidth = 24.dp). The tallest stack fills the height unless you pass maxValue. The legend is off by default; turn it on with showLegend = true, or pass your own action in place of the trend label.

Horizontal bar

val bars = listOf(
    HorizontalBar(value = 31f, total = 60f),
    HorizontalBar(value = 56f, total = 80f),
    HorizontalBar(value = 30f, total = 51f),
    HorizontalBar(value = 21f, total = 32f),
    HorizontalBar(value = 38f, total = 63f),
)

Chart card

HorizontalBarChartCard(
    title = "Horizontal bar chart with border radius",
    bars = bars,
    name = "Andres",
    role = "Team Leader",
    avatar = { ChartInitialsAvatar(text = "A") }, // or your own Image clipped to a circle
    action = { ChartPillButton(text = "PROFILE", onClick = { /* open profile */ }) },
    description = "Tasks finished out of tasks assigned in each of the last five sprints.",
)

Chart only

HorizontalBarChart(
    bars = bars,
    modifier = Modifier.fillMaxWidth(),
)

Each bar is a dark fill (value) drawn over a lighter track (total). The chart sets its own height from the number of bars, barHeight and barSpacing, so only give it a width. The longest track fills the width unless you pass maxValue. Bars are pills by default; pass HorizontalBarChartDefaults.style(cornerRadius = 4.dp) for squarer ends. The profile row is left out when avatar, name, role and action are all null, and the description is cut off after two lines (HorizontalBarChartCardDefaults.style(descriptionMaxLines = …)).

Ranked bar

val bars = listOf(
    RankedBar(label = "Norway", value = 89f),
    RankedBar(label = "Australia", value = 81f),
    RankedBar(label = "Switzerland", value = 74f),
    RankedBar(label = "Canada", value = 35f),
)

Chart card

RankedBarChartCard(
    title = "Average of the first economies",
    bars = bars,
    description = "Economy score of the leading countries, highest first.",
    listTitle = "List of countries",
    listCaption = "${bars.size} countries",
    footer = "Scores are an index out of 100.",
)

Chart only

RankedBarChart(
    bars = bars,
    modifier = Modifier.fillMaxWidth(),
)

Bars are sorted by value, longest on top, and drawn flush so they form a staircase. Each one takes the next colour of RankedBarChartDefaults.Colors (navy to pale sky); pass your own list with RankedBarChartDefaults.style(colors = …), or give a single bar a color. Labels are written inside the bars in white or black, whichever reads better on that colour, and move just past the bar's end when they don't fit (outsideLabelColor). The chart sets its own height from the number of bars and barHeight, so only give it a width. The longest bar fills the width unless you pass maxValue. The list header row is left out when listTitle and listCaption are both null.

Overlapping area

val series = listOf(
    AreaSeries(label = "2011", values = listOf(78f, 40f, 26f, 33f, 0f, 19f, 37f), color = OverlappingAreaChartDefaults.FirstColor),
    AreaSeries(label = "2012", values = listOf(28f, 98f, 70f, 78f, 60f, 10f, 61f), color = OverlappingAreaChartDefaults.SecondColor),
)

Chart card

var region by remember { mutableIntStateOf(0) }
OverlappingAreaChartCard(
    title = "Estimated Worldwide Population",
    series = series,
    filters = listOf("America", "Europe", "Asia"),
    selectedFilter = region,
    onFilterSelected = { region = it },
    description = "Population index per month, 2011 laid over 2012.",
    name = "Ralph Edwards",
    role = "Team Leader",
    avatar = { ChartInitialsAvatar(text = "R") },
    profileAction = { ChartCircleButton(onClick = { /* open chat */ }) { ChartChatIcon() } },
    footer = "Figures are an index, not head counts.",
)

Chart only

OverlappingAreaChart(
    series = series,
    modifier = Modifier.fillMaxWidth().height(160.dp),
)

Each series joins its values with straight lines, spread evenly from edge to edge, and is filled down to 0 at the bottom. Series are drawn in order, so the last is on top; give their colours some transparency (as FirstColor and SecondColor do) so the areas behind show through and overlaps read darker. The tallest value of any series reaches the top unless you pass maxValue. Pass OverlappingAreaChartDefaults.style(lineWidth = 2.dp) to outline each area's top edge. The filter row is left out when filters is empty and the profile row when avatar, name, role and profileAction are all null; filters are only tappable when onFilterSelected is given. The header colour, chip colours and spacings live in OverlappingAreaChartCardDefaults.style(...).

Mirrored area

val upper = listOf(
    AreaSeries(label = "Zone 4", values = listOf(60f, 30f, 75f, 85f, 40f, 100f), color = MirroredAreaChartDefaults.UpperColors[0]),
    AreaSeries(label = "Zone 1", values = listOf(12f, 8f, 20f, 25f, 15f, 12f), color = MirroredAreaChartDefaults.UpperColors[3]),
)
val lower = listOf(
    AreaSeries(label = "Zone 5", values = listOf(60f, 45f, 70f, 50f, 95f, 40f), color = MirroredAreaChartDefaults.LowerColors[0]),
    AreaSeries(label = "Zone 3", values = listOf(30f, 45f, 22f, 50f, 28f, 55f), color = MirroredAreaChartDefaults.LowerColors[2]),
)

Chart card

MirroredAreaChartCard(
    title = "Intensity",
    subtitle = "September 2021",
    description = "Time spent in each heart-rate zone, day by day.",
    upperSeries = upper,
    lowerSeries = lower,
    summaryLabel = "Intensity zones",
    summaryValue = "80%",
)

Chart only

MirroredAreaChart(
    upperSeries = upper,
    lowerSeries = lower,
    modifier = Modifier.fillMaxWidth().height(240.dp),
)

upperSeries grow up from the baseline and lowerSeries hang down from it, each joined with a smooth curve and spread edge to edge. Within each half the last series is drawn in front, so put the tallest first and give the colours some transparency (UpperColors and LowerColors are ready-made, back to front). Both halves share one scale: the tallest value of any series reaches the edge unless you pass maxValue. MirroredAreaChartDefaults.style(...) sets the smoothing (0 for straight lines), the share of height above the baseline (upperFraction) and the baseline colour. In the card, the chart runs to the card's edges; the footer's overlapping swatches default to MirroredAreaChartDefaults.ZoneColors, and the footer is left out when summaryLabel, summaryValue, swatches and action are all empty. Set swatchBorderColor in MirroredAreaChartCardDefaults.style(...) to your card's background.

Stacked column

val series = listOf(
    BarSeries(label = "Apple", values = listOf(100f, 73f, 55f, 85f, 27f), color = StackedColumnChartDefaults.FirstColor),
    BarSeries(label = "Banana", values = listOf(100f, 73f, 55f, 85f, 27f), color = StackedColumnChartDefaults.SecondColor),
)

Chart card

var month by remember { mutableIntStateOf(1) }
StackedColumnChartCard(
    title = "Stacked column chart",
    series = series,
    tabs = listOf("Nov", "Dec", "Jan", "Feb", "Mar", "Apr"),
    selectedTab = month,
    onTabSelected = { month = it },
    description = "Apples and bananas sold each week, side by side.",
    name = "Jerome Bell",
    role = "Marketing Coordinator",
    avatar = { ChartInitialsAvatar(text = "J") },
    profileAction = { ChartChatIcon() },
)

Chart only

StackedColumnChart(
    series = series,
    modifier = Modifier.fillMaxWidth().height(136.dp),
)

Each column holds value i of every series as a stripe, side by side, with the first series on the left. Stripes split the column's width and each is as tall as its own value. Columns are spread edge to edge, and the tallest value reaches the top unless you pass maxValue. StackedColumnChartDefaults.style(...) sets columnSpacing, seriesSpacing (0 keeps the stripes flush) and maxColumnWidth. In the card, the default action is a glowing StackedColumnSparkline. The tab row is left out when tabs is empty, and the profile footer when avatar, name, role and profileAction are all null. Tabs can only be tapped when onTabSelected is given. Tab and footer colours live in StackedColumnChartCardDefaults.style(...). ChartSparkIcon also takes haloColor and haloWidth if you want its glow elsewhere.

Floating bar

val bars = listOf(
    FloatingBar(low = 2800f, high = 5000f, color = FloatingBarChartDefaults.PrimaryColor),
    FloatingBar(low = 1800f, high = 3000f, color = FloatingBarChartDefaults.LightColor),
    FloatingBar(low = 500f, high = 5000f, color = FloatingBarChartDefaults.AccentColor),
)

Chart card

var range by remember { mutableIntStateOf(2) }
FloatingBarChartCard(
    title = "Statistic",
    description = "Minim dolor in amet nulla laboris enim dolore consequatt.",
    bars = bars,
    action = { ChartCircleButton(onClick = {}) { ChartSortIcon() } },
    caption = "Year 2021",
    ranges = listOf("24h", "1d", "3d", "1w", "3w", "1m"),
    selectedRange = range,
    onRangeSelected = { range = it },
)

Chart only

FloatingBarChart(
    bars = bars,
    modifier = Modifier.fillMaxWidth().height(168.dp),
)

Each bar spans from its low to its high value instead of standing on the baseline, and takes its own colour. The axis runs from 0 to maxValue in gridSteps equal steps (4 by default). Without maxValue, the highest value is rounded up so every step is a round number (1, 2, 2.5 or 5 × 10ⁿ). Labels go through labelFormatter, which defaults to FloatingBarChartDefaults.formatValue (8000f becomes 8k). Bars are spread edge to edge across the grid and grow out from their middles when they animate in. FloatingBarChartDefaults.style(...) sets barWidth, barInset, the grid's colour and dash (gridDashLength = 0.dp draws solid lines) and the label style. In the card, the chip row is left out when ranges is empty, and chips can only be tapped when onRangeSelected is given. Chip colours live in FloatingBarChartCardDefaults.style(...). ChartSortIcon is the three-line glyph from the header.

Heatmap

// Rows from top to bottom, each from left to right.
val values = listOf(
    listOf(0f, 7f, 0f, 12f, 14f, 0f),
    listOf(0f, 8f, 0f, 0f, 13f, 2f),
    listOf(3f, 0f, 6f, 2f, 0f, 11f),
)

Chart card

var year by remember { mutableIntStateOf(0) }
HeatmapChartCard(
    title = "Sales per employee per month",
    subtitle = "263 contributions in the last year",
    values = values,
    action = { ChartCircleButton(onClick = {}) { ChartSettingsIcon() } },
    tabs = listOf("2016", "2017", "2018", "2019"),
    selectedTab = year,
    onTabSelected = { year = it },
    description = "Minim dolor in amet nulla laboris enim dolore consequatt.",
    columnLabels = listOf("Nov", "Dec", "Jan", "Feb"),
    note = "Learn how we count contributions",
    footerText = "Show more activity",
    onFooterClick = {},
)

Chart only

HeatmapChart(
    values = values,
    columnLabels = listOf("Nov", "Dec", "Jan", "Feb"),
    modifier = Modifier.fillMaxWidth(),
)

Each cell takes one of colors (four shades from HeatmapChartDefaults.Colors by default, emptiest first). A value of 0 or less takes the first colour, and the rest are split evenly between the other colours up to maxValue, which defaults to the highest value. Shorter rows are padded with empty cells. Columns are spread edge to edge, and columnLabels are spread evenly above them, the first over the first column and the last over the last. Unless you give it a height, the chart is as tall as its rows at cellSize; cells shrink when the grid would not fit. Cells pop in column by column, then blend to their new colours when the data changes. HeatmapChartDefaults.style(...) sets cellSize, cellCornerRadius, minColumnSpacing, rowSpacing and the label style. In the card, the tab row is left out when tabs is empty, tabs can only be tapped when onTabSelected is given, the legend is left out when showLegend is false, and the footer button when footerText is null. Tab, legend and footer colours live in HeatmapChartCardDefaults.style(...). HeatmapLegend can be used on its own.

Styling

Every chart card has three style layers: the card, the legend and the chart itself.

VerticalBarChartCard(
    title = "Revenue",
    upperSeries = series,
    cardStyle = ChartCardDefaults.style(
        backgroundColor = MaterialTheme.colorScheme.surface,
        border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
    ),
    legendStyle = ChartLegendDefaults.style(),
    chartStyle = VerticalBarChartDefaults.style(
        barWidth = 16.dp,
        showGridLines = false,
    ),
    animationSpec = tween(durationMillis = 1_000),
)

The bare chart takes only the chart layer, through its style parameter (VerticalBarChart(style = VerticalBarChartDefaults.style(...))).

Sample app

The :app module is a showcase app with one screen per chart. Each screen has Shuffle data and Reset buttons so you can watch the charts animate. It uses Hilt and MVI ViewModels, and it follows the system light or dark theme.

./gradlew :app:installDebug

Project structure

ComposeCharts/
├── charts/   # The library: chart composables, styles, shared ChartCard and ChartLegend
├── app/      # Showcase app (Hilt + MVI) that demos every chart
└── docs/     # Documentation website (index.html), chart GIFs and logo

Contributing

Issues and pull requests are welcome. When you add a chart:

  1. Add the chart composable, its XxxStyle and XxxDefaults, plus a XxxChartCard wrapper in :charts.
  2. Add a ChartSample entry in ChartSampleRepository and a screen in :app.
  3. Add a test to RecordChartGifs in :app, run ./scripts/record-chart-gifs.sh to render the GIFs into docs/gifs/ (needs ffmpeg), and add the chart to the tables above (the Preview table holds three GIFs per row).
  4. Add an entry to the CHARTS list in docs/index.html so the chart gets its own page on the website.

Publishing a release

The :charts module is published with the vanniktech maven-publish plugin. The Central Portal token and the GPG signing key live in ~/.gradle/gradle.properties, never in this repo:

mavenCentralUsername=<portal token username>
mavenCentralPassword=<portal token password>
signingInMemoryKeyId=<last 8 chars of the key id>
signingInMemoryKeyPassword=<key passphrase>
signingInMemoryKey=<ascii-armored private key, on one line>

To release:

  1. Bump VERSION_NAME in gradle.properties.
  2. Optionally test the build locally with ./gradlew :charts:publishToMavenLocal.
  3. Run ./gradlew :charts:publishToMavenCentral. The release is published automatically and shows up on Maven Central within about 30 minutes.

Licensed under the Apache License 2.0.

Made with ❤️ and Jetpack Compose by Jayant Kumar

About

Beautiful, animated, fully customizable charts for Jetpack Compose.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages