Skip to content

ois0886/compose-chart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

69 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

compose-chart

Jetpack Compose์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋ณ๊ณ  ๋…๋ฆฝ์ ์ธ ์ฐจํŠธ UI ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋งŒ ๋„˜๊ธฐ๋ฉด ๋์ž…๋‹ˆ๋‹ค.

Maven Central License API

Charts

Line Chart Bar Chart Donut Chart
Gauge Chart Radar Chart Pie Chart

๋‹คํฌ ๋ชจ๋“œ

Color.Unspecified + isSystemInDarkTheme() ํŒจํ„ด์œผ๋กœ ๊ทธ๋ฆฌ๋“œ/์ถ•/๊ฒŒ์ด์ง€ ํŠธ๋ž™/ ๋ ˆ์ด๋” ์›น ์ƒ‰์ƒ์ด ๋‹คํฌ ๋ชจ๋“œ์— ์ž๋™ ๋Œ€์‘ํ•ฉ๋‹ˆ๋‹ค. ๋‹คํฌ ๋ชจ๋“œ ์ „์šฉ ์Šคํƒ€์ผ ์„ค์ •์€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ“ท ๋‹คํฌ ๋ชจ๋“œ ์Šคํฌ๋ฆฐ์ƒท ์ถ”๊ฐ€ ์˜ˆ์ •: screenshots/{chart}-dark.png

Why?

๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™”๋Š” ์•ฑ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, Compose์—์„œ ๋ฐ”๋กœ ์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋ฒผ์šด ์ฐจํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ์ ‘๊ทผ ๋ฐฉ์‹๋“ค์€ Material3์— ์˜์กดํ•˜๊ฑฐ๋‚˜, ์„ค์ •์ด ๋ณต์žกํ•˜๊ฑฐ๋‚˜, ํŠน์ • ํ”„๋กœ์ ํŠธ์™€ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. compose-chart๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค:

  • UI ์˜์กด์„ฑ ์ œ๋กœ โ€” Compose Foundation๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Material3๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.
  • 6๊ฐ€์ง€ ์ฐจํŠธ โ€” Line, Bar, Donut, Gauge, Radar, Pie๋ฅผ ํ•˜๋‚˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ.
  • ์™„์ „ํ•œ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• โ€” ์ƒ‰์ƒ, ์ถ•, ์• ๋‹ˆ๋ฉ”์ด์…˜, ํ„ฐ์น˜ ์ƒํ˜ธ์ž‘์šฉ๊นŒ์ง€ ๋ชจ๋“  ๊ฒƒ์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ธฐ๋ณธ๊ฐ’๋„ ์ž˜ ์žกํ˜€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์•ˆ์ „ํ•œ ์ž…๋ ฅ ์ฒ˜๋ฆฌ โ€” NaN, Infinity, ์Œ์ˆ˜, ๋นˆ ๋ฐ์ดํ„ฐ๋„ ํฌ๋ž˜์‹œ ์—†์ด ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ์ ‘๊ทผ์„ฑ ๊ธฐ๋ณธ ์ง€์› โ€” ์ฐจํŠธ ์š”์•ฝ๊ณผ ์„ ํƒ ์ƒํƒœ๋ฅผ ์Šคํฌ๋ฆฐ๋ฆฌ๋”์šฉ semantics๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Setup

ํ˜„์žฌ ๋ฌธ์„œ ๊ธฐ์ค€ ์ตœ์‹  ๋ฆด๋ฆฌ์Šค๋Š” v1.3.1์ž…๋‹ˆ๋‹ค.

// build.gradle.kts
dependencies {
    implementation("io.github.ois0886:compose-chart:1.3.1")
}

Quick Start

์„  ์ฐจํŠธ

LineChart(
    data = LineChartData.fromValues(
        values = listOf(10f, 25f, 18f, 32f, 22f),
        xLabels = listOf("1์›”", "2์›”", "3์›”", "4์›”", "5์›”"),
    ),
    modifier = Modifier.fillMaxWidth().height(200.dp),
)

๋ง‰๋Œ€ ์ฐจํŠธ

BarChart(
    data = BarChartData.simple(
        values = listOf(30f, 45f, 25f, 60f),
        labels = listOf("1๋ถ„๊ธฐ", "2๋ถ„๊ธฐ", "3๋ถ„๊ธฐ", "4๋ถ„๊ธฐ"),
    ),
    modifier = Modifier.fillMaxWidth().height(200.dp),
)

๋„๋„› ์ฐจํŠธ

DonutChart(
    data = DonutChartData(
        slices = listOf(
            DonutSlice(40f, "์‹๋น„"),
            DonutSlice(25f, "๊ตํ†ต"),
            DonutSlice(35f, "๊ธฐํƒ€"),
        ),
    ),
    modifier = Modifier.size(200.dp),
)

๊ฒŒ์ด์ง€ ์ฐจํŠธ

GaugeChart(
    data = GaugeChartData(value = 72f, maxValue = 100f, label = "์ ์ˆ˜"),
    modifier = Modifier.size(180.dp),
)

๋ ˆ์ด๋” ์ฐจํŠธ

RadarChart(
    data = RadarChartData.single(
        values = listOf(80f, 65f, 90f, 70f, 85f),
        axisLabels = listOf("STR", "DEX", "INT", "WIS", "CHA"),
    ),
    modifier = Modifier.size(200.dp),
)

ํŒŒ์ด ์ฐจํŠธ

PieChart(
    data = DonutChartData.fromValues(30f, 25f, 45f),
    modifier = Modifier.size(200.dp),
)

Features (v1.3.1)

README ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ํ…Œ์ŠคํŠธ์—์„œ๋„ ํ•จ๊ป˜ ์œ ์ง€๋˜์–ด, ๋ฌธ์„œ ์Šค๋‹ˆํŽซ์ด ์‹ค์ œ API์™€ ์–ด๊ธ‹๋‚˜์ง€ ์•Š๋„๋ก ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. v1.3.1์€ ๊ณต๊ฐœ API์™€ ์‹œ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ Line/Bar/Donut/Pie/Radar ๋ Œ๋”๋ง hot path์˜ ๋ฐ˜๋ณต ๊ณ„์‚ฐ๊ณผ ํ• ๋‹น์„ ์ค„์ธ ์„ฑ๋Šฅ ๊ฐœ์„  ๋ฆด๋ฆฌ์Šค์ž…๋‹ˆ๋‹ค.

์คŒ & ํŒฌ

Line, Bar ์ฐจํŠธ์—์„œ ํ•€์น˜ ์คŒ๊ณผ ๋“œ๋ž˜๊ทธ ํŒฌ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋”๋ธ”ํƒญ์œผ๋กœ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.

val zoomState = rememberChartZoomState()

LineChart(
    data = data,
    zoomState = zoomState,
)

์ฐจํŠธ ์ด๋ฏธ์ง€ ์บก์ฒ˜

์ฐจํŠธ๋ฅผ ImageBitmap์œผ๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. capture()๋Š” suspend ํ•จ์ˆ˜์ด๋ฏ€๋กœ rememberCoroutineScope() ํ˜น์€ LaunchedEffect์—์„œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

val captureState = rememberChartCaptureState()
val scope = rememberCoroutineScope()

Column {
    LineChart(
        data = data,
        modifier = Modifier
            .fillMaxWidth()
            .height(200.dp)
            .chartCaptureModifier(captureState),
    )

    Button(onClick = {
        scope.launch {
            val bitmap: ImageBitmap = captureState.capture()
            // bitmap.asAndroidBitmap()์„ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๊ณต์œ  Intent์— ์ฒจ๋ถ€
        }
    }) {
        Text("์ด๋ฏธ์ง€๋กœ ์ €์žฅ")
    }
}

Modifier.chartCaptureModifier(captureState)๋Š” ์–ด๋А ์ฐจํŠธ์—๋„ ๋™์ผํ•˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋๋‚œ ๋’ค ์บก์ฒ˜ํ•˜๋ฉด ์ตœ์ข… ์ƒํƒœ๊ฐ€ ๋‹ด๊ธด ์ด๋ฏธ์ง€๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๋ฒ”๋ก€

๋ฒ”๋ก€ ํ•ญ๋ชฉ์„ ํƒญํ•˜์—ฌ ์‹œ๋ฆฌ์ฆˆ๋ฅผ ํ† ๊ธ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

val items = remember {
    mutableStateListOf(
        LegendItem(color = Color.Blue, label = "๋งค์ถœ", enabled = true),
        LegendItem(color = Color.Red, label = "๋น„์šฉ", enabled = true),
    )
}

ChartLegend(
    items = items,
    onItemClick = { index ->
        items[index] = items[index].copy(enabled = !items[index].enabled)
    },
)

ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ

๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ๊ทธ๋ฃน ๋ง‰๋Œ€ ์ฐจํŠธ
BarChartData.grouped(
    seriesValues = listOf(listOf(10f, 20f), listOf(15f, 25f)),
    labels = listOf("1์›”", "2์›”"),
)

// Map์—์„œ ๋ฉ€ํ‹ฐ ์‹œ๋ฆฌ์ฆˆ ๋ผ์ธ ์ฐจํŠธ
LineChartData.fromMap(
    seriesMap = mapOf("๋งค์ถœ" to listOf(10f, 20f), "๋น„์šฉ" to listOf(5f, 15f)),
    xLabels = listOf("Q1", "Q2"),
)

// ๊ฐ’๋งŒ์œผ๋กœ ๋„๋„› ์ฐจํŠธ
DonutChartData.fromValues(40f, 25f, 20f, 15f)

Y์ถ• ๋ฒ”์œ„ ์ˆ˜๋™ ์„ค์ •

LineChart(
    data = data,
    style = LineChartStyle(
        axis = AxisStyle(
            showYAxis = true,
            yAxisMin = 0f,    // ์ตœ์†Ÿ๊ฐ’ ๊ณ ์ •
            yAxisMax = 100f,  // ์ตœ๋Œ“๊ฐ’ ๊ณ ์ •
        ),
    ),
)

ํฐํŠธ ์ปค์Šคํ…€

์ถ•, ํˆดํŒ, ๋ฒ”๋ก€, ๊ฒŒ์ด์ง€ ์ค‘์•™ ํ…์ŠคํŠธ์˜ ํฐํŠธ ๊ตต๊ธฐ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

LineChart(
    data = data,
    style = LineChartStyle(
        axis = AxisStyle(fontWeight = FontWeight.Bold),
        tooltip = TooltipStyle(fontWeight = FontWeight.Medium),
    ),
)

Customization

์ƒ‰์ƒ

๊ธฐ๋ณธ ํŒ”๋ ˆํŠธ(ChartDefaults.colors)๋Š” 6๊ฐœ ์ƒ‰์œผ๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ, ๋ฉ€ํ‹ฐ ์‹œ๋ฆฌ์ฆˆ ์ฐจํŠธ์—์„œ ์ˆœ์„œ๋Œ€๋กœ ๋ฐฐ์ •๋˜๊ณ  ์‹œ๋ฆฌ์ฆˆ ์ˆ˜๊ฐ€ 6๊ฐœ๋ฅผ ๋„˜์œผ๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ˆœํ™˜ํ•ฉ๋‹ˆ๋‹ค.

# Name HEX
1 Blue #3182F6
2 Green #48BB78
3 Orange #ED8936
4 Red #E53E3E
5 Purple #9F7AEA
6 Teal #38B2AC
// ์ปค์Šคํ…€ ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ
LineChart(
    data = data,
    colors = listOf(Color.Red, Color.Blue, Color.Green),
)

// ์‹œ๋ฆฌ์ฆˆ๋ณ„ ๊ฐœ๋ณ„ ์ƒ‰์ƒ
LineChart(
    data = LineChartData(
        series = listOf(
            LineSeries(points = points1, color = Color.Red),
            LineSeries(points = points2, color = Color.Blue),
        ),
    ),
)

์Šคํƒ€์ผ

LineChart(
    data = data,
    style = LineChartStyle(
        curved = true,              // ๊ณก์„ /์ง์„ 
        showDots = true,            // ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ ํ‘œ์‹œ
        gradientFill = true,        // ๊ทธ๋ž˜๋””์–ธํŠธ ์ฑ„์šฐ๊ธฐ
        lineWidth = 3.dp,           // ์„  ๋‘๊ป˜
        animationDurationMs = 1000, // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ๊ฐ„
        axis = AxisStyle(
            showYAxis = true,
            yLabelCount = 5,
            yAxisFormatter = { value -> "${value.toLong()}%" },
        ),
        grid = GridStyle(
            showHorizontalLines = true,
            dashPattern = listOf(10f, 5f),
        ),
    ),
)

ํ„ฐ์น˜ ์ƒํ˜ธ์ž‘์šฉ

onSelectionChanged๋Š” 6๊ฐœ ์ฐจํŠธ์—์„œ ๊ณตํ†ต์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ์ฝœ๋ฐฑ์œผ๋กœ, ์ฐจํŠธ๋ณ„ ChartSelection ํ•˜์œ„ ํƒ€์ž…(Line/Bar/Donut/Radar/Gauge)์„ ๋ฐฉ์ถœํ•ฉ๋‹ˆ๋‹ค.

LineChart(
    data = data,
    onSelectionChanged = { selection: ChartSelection.Line ->
        println("์‹œ๋ฆฌ์ฆˆ ${selection.seriesIndex}, " +
            "ํฌ์ธํŠธ ${selection.pointIndex}: ${selection.point.y}")
    },
)

DonutChart(
    data = data,
    onSelectionChanged = { selection: ChartSelection.Donut ->
        println("${selection.slice.label}: ${selection.slice.value}")
    },
)

GaugeChart(
    data = data,
    onSelectionChanged = { selection: ChartSelection.Gauge ->
        println("ํ˜„์žฌ ๊ฐ’ ${selection.value}, ์ง„ํ–‰๋ฅ  ${selection.ratio}")
    },
)

๊ธฐ์กด์˜ onPointSelected/onBarSelected/onSliceSelected/onAxisSelected ์ฝœ๋ฐฑ์€ ์†Œ์Šค ํ˜ธํ™˜์„ ์œ„ํ•ด ์œ ์ง€๋˜์ง€๋งŒ v2.0์—์„œ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์„ ํƒ ์ฝœ๋ฐฑ์€ ๋™์ผํ•œ ์„ ํƒ ์ƒํƒœ์˜ redraw/recomposition๋งˆ๋‹ค ๋ฐ˜๋ณต ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ , ์„ ํƒ ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

์„ฑ๋Šฅ ํŒ

  • v1.3.1๋ถ€ํ„ฐ ์ฐจํŠธ ๋‚ด๋ถ€์—์„œ ์ฃผ์š” ํŒŒ์ƒ ๋ฐ์ดํ„ฐ์™€ draw ๋ฆฌ์†Œ์Šค๋ฅผ ์บ์‹œํ•˜์ง€๋งŒ, ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์—์„œ๋„ ๋ถˆํ•„์š”ํ•œ ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์ค„์ด๋ฉด ํšจ๊ณผ๊ฐ€ ๋” ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.
  • ์ฐจํŠธ data์™€ style์€ ๊ฐ€๋Šฅํ•˜๋ฉด remember ๋˜๋Š” ์ƒ์œ„ ์ƒํƒœ๋กœ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•˜์„ธ์š”. ๊ฐ™์€ ๊ฐ’์„ ๋งค recomposition๋งˆ๋‹ค ์ƒˆ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค๋ฉด ์ฐจํŠธ๊ฐ€ ๋‹ค์‹œ ๊ณ„์‚ฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๊ฐ€ ๋งŽ๋‹ค๋ฉด showDots, X์ถ•/slice/radar label, ๊ธด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ•„์š”ํ•œ ํ™”๋ฉด์—์„œ๋งŒ ์ผœ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • ๋Œ€๋Ÿ‰์˜ LineChart ๋ฐ์ดํ„ฐ๋Š” ์‹œ๊ฐ„์ˆœ/์ธ๋ฑ์Šค์ˆœ์ฒ˜๋Ÿผ x ๊ฐ’์ด ์˜ค๋ฆ„์ฐจ์ˆœ์ด ๋˜๋„๋ก ์ „๋‹ฌํ•˜๋ฉด ํ„ฐ์น˜ ์„ ํƒ ํƒ์ƒ‰์ด ๋” ๋น ๋ฅด๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ •๋ ฌ๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋„ ๊ณ„์† ์ง€์›๋ฉ๋‹ˆ๋‹ค.
  • Modifier.chartCaptureModifier()๋Š” offscreen ๊ธฐ๋ก ๋น„์šฉ์ด ์žˆ์œผ๋ฏ€๋กœ ์‹ค์ œ ์ด๋ฏธ์ง€ ๋‚ด๋ณด๋‚ด๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ์ฐจํŠธ์—๋งŒ ์ ์šฉํ•˜์„ธ์š”.

๋ฒ”๋ก€

Column {
    LineChart(data = data, colors = colors)
    ChartLegend(
        items = data.series.mapIndexed { i, s ->
            LegendItem(color = colors[i % colors.size], label = s.label)
        },
    )
}

Chart Types

์ฐจํŠธ Composable ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค ์šฉ๋„
์„  ์ฐจํŠธ LineChart LineChartData ์‹œ๊ณ„์—ด, ์ถ”์„ธ
๋ง‰๋Œ€ ์ฐจํŠธ BarChart BarChartData ๋น„๊ต, ๋ถ„ํฌ
๋„๋„› ์ฐจํŠธ DonutChart DonutChartData ๋น„์œจ, ๊ตฌ์„ฑ
๊ฒŒ์ด์ง€ ์ฐจํŠธ GaugeChart GaugeChartData ์ง„ํ–‰๋„, ๋‹ฌ์„ฑ๋ฅ 
๋ ˆ์ด๋” ์ฐจํŠธ RadarChart RadarChartData ๋‹ค์ถ• ๋น„๊ต
ํŒŒ์ด ์ฐจํŠธ PieChart DonutChartData ๋น„์œจ (๋„๋„›์˜ ํŠน์ˆ˜ ์ผ€์ด์Šค)

Development Highlights

  • Pure Compose Foundation โ€” Material3 ์˜์กด ์—†์ด Foundation์˜ Canvas, BasicText๋งŒ ์‚ฌ์šฉํ•˜์—ฌ, ์–ด๋–ค ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ์“ฐ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ๋„ ์ถฉ๋Œ ์—†์ด ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ์•ˆ์ „ํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ โ€” NaN, Infinity, ์Œ์ˆ˜, ๋นˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋“  ์ฐจํŠธ์—์„œ ๋ฐฉ์–ด์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. safeX, safeY ํŒจํ„ด์œผ๋กœ ์ž˜๋ชป๋œ ์ž…๋ ฅ์ด ํฌ๋ž˜์‹œ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ˆœ์ˆ˜ ํ•จ์ˆ˜ & ํ…Œ์ŠคํŠธ โ€” ์ขŒํ‘œ ๊ณ„์‚ฐ, ๋ฒ”์œ„ ๊ณ„์‚ฐ, ํ„ฐ์น˜ ๊ฐ์ง€ ๋กœ์ง์ด internal/math/์— ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์œผ๋ฉฐ, JVM ์œ ๋‹› ํ…Œ์ŠคํŠธ์™€ Compose UI ํ…Œ์ŠคํŠธ๊ฐ€ ์ „์ฒด ์ฐจํŠธ๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  • ๋ Œ๋”๋ง ์„ฑ๋Šฅ โ€” Canvas draw ์ค‘ side effect๋ฅผ ํ”ผํ•˜๊ณ , ๋ฐ์ดํ„ฐ/ํฌ๊ธฐ ๊ธฐ๋ฐ˜ ๋ ˆ์ด์•„์›ƒ๊ณผ ๊ณตํ†ต draw ๋ฆฌ์†Œ์Šค๋ฅผ ์บ์‹œํ•ด animation redraw ๋น„์šฉ์„ ์ค„์ž…๋‹ˆ๋‹ค.
  • ์คŒ & ํŒฌ โ€” ChartZoomState๋ฅผ ํ†ตํ•œ ํ•€์น˜ ์คŒ/๋“œ๋ž˜๊ทธ ํŒฌ ์ง€์›. Canvas withTransform์œผ๋กœ ์ขŒํ‘œ ์—ญ๋ณ€ํ™˜ ์ฒ˜๋ฆฌ.
  • ์ด๋ฏธ์ง€ ์บก์ฒ˜ โ€” GraphicsLayer API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ฐจํŠธ๋ฅผ ImageBitmap์œผ๋กœ ๋‚ด๋ณด๋‚ด๊ธฐ.
  • ํ…Œ๋งˆ ์ธ์‹ โ€” Color.Unspecified ํŒจํ„ด์œผ๋กœ ๋‹คํฌ/๋ผ์ดํŠธ ํ…Œ๋งˆ์— ๋งž๋Š” ๊ธฐ๋ณธ ์ƒ‰์ƒ์„ ์ž๋™ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ ‘๊ทผ์„ฑ ์ง€์› โ€” ๊ฐ ์ฐจํŠธ์— semantics๋กœ ์ฝ˜ํ…์ธ  ์„ค๋ช…์„ ์ œ๊ณตํ•˜์—ฌ ์Šคํฌ๋ฆฐ ๋ฆฌ๋”(TalkBack)๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

Requirements

  • Min SDK 24 (Android 7.0)
  • Jetpack Compose (Foundation)

License

Copyright 2026 Inseong

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.

About

A various chart library for Jetpack Compose

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages