的
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,31 @@
|
||||
plugins {
|
||||
id("ycharts.android.application")
|
||||
id("ycharts.android.application.compose")
|
||||
id("ycharts.android.test")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "co.yml.ycharts.app"
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
defaultConfig {
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
applicationId = "co.yml.ycharts.app"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(mapOf("path" to ":YChartsLib")))
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,24 @@
|
||||
package co.yml.ycharts.app
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("co.yml.ycharts.app", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.YCharts"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.BarChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_bar_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.LineChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_line_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.WaveChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_wave_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.PieChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_pie_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.DonutChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_donut_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.CombinedLineAndBarChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_combined_line_bar_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name="co.yml.ycharts.app.presentation.BubbleChartActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_bubble_chart"
|
||||
android:theme="@style/Theme.YCharts" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.YCharts">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,150 @@
|
||||
package co.yml.ycharts.app
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.ycharts.app.presentation.*
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
ChartsMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun ChartsMenu() {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = { AppBar() }) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(it)
|
||||
.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
ChartButton(title = getString(R.string.title_bar_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, BarChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
ChartButton(title = getString(R.string.title_line_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, LineChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
|
||||
ChartButton(title = getString(R.string.title_wave_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, WaveChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
|
||||
ChartButton(title = getString(R.string.title_pie_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, PieChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
ChartButton(title = getString(R.string.title_donut_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, DonutChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
ChartButton(title = getString(R.string.title_bar_with_line_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, CombinedLineAndBarChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
ChartButton(title = getString(R.string.bubble_chart), onClick = {
|
||||
startActivity(
|
||||
Intent(
|
||||
this@MainActivity, BubbleChartActivity::class.java
|
||||
)
|
||||
)
|
||||
addActivityInOutAnim()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun addActivityInOutAnim() {
|
||||
overridePendingTransition(
|
||||
R.anim.move_right_in_activity, R.anim.move_left_out_activity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AppBar() {
|
||||
TopAppBar(modifier = Modifier.fillMaxWidth(),
|
||||
backgroundColor = YChartsTheme.colors.button,
|
||||
elevation = 6.dp,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.app_name),
|
||||
color = YChartsTheme.colors.text,
|
||||
textAlign = TextAlign.Center,
|
||||
style = YChartsTheme.typography.header
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChartButton(title: String, onClick: () -> Unit) {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.padding(end = 10.dp, start = 10.dp)
|
||||
.fillMaxWidth()
|
||||
.height(50.dp),
|
||||
onClick = onClick,
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = YChartsTheme.colors.button)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = YChartsTheme.typography.button,
|
||||
color = YChartsTheme.colors.text
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun DefaultPreview() {
|
||||
ChartButton(title = "Chart", onClick = {})
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.charts.axis.AxisData
|
||||
import co.yml.charts.axis.DataCategoryOptions
|
||||
import co.yml.charts.common.components.Legends
|
||||
import co.yml.charts.common.extensions.getMaxElementInYAxis
|
||||
import co.yml.charts.common.model.LegendsConfig
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.barchart.BarChart
|
||||
import co.yml.charts.ui.barchart.GroupBarChart
|
||||
import co.yml.charts.ui.barchart.StackedBarChart
|
||||
import co.yml.charts.ui.barchart.models.*
|
||||
import co.yml.ycharts.app.R
|
||||
import kotlin.random.Random
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
/**
|
||||
* Bar chart activity
|
||||
*
|
||||
* @constructor Create empty Bar chart activity
|
||||
*/
|
||||
class BarChartActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.title_bar_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
LazyColumn(content = {
|
||||
items(6) { item ->
|
||||
when (item) {
|
||||
0 ->{ Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.barchart_solid_colors),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
BarchartWithSolidBars()
|
||||
}
|
||||
1 -> { Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.barchart_gradient_colors),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
BarchartWithGradientBars()}
|
||||
2 ->{
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.barchart_background_color),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
BarchartWithBackgroundColor()
|
||||
}
|
||||
3 ->{
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.horizontal_bar_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
HorizontalBarChart()
|
||||
}
|
||||
|
||||
4 ->{
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.grouped_bar_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
VerticalGroupBarChart()
|
||||
}
|
||||
5 ->{
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.stacked_barchart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
VerticalStackedBarChart()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Barchart with solid bars
|
||||
*
|
||||
*/
|
||||
@Composable
|
||||
private fun BarchartWithSolidBars() {
|
||||
val maxRange = 50
|
||||
val barData = DataUtils.getBarChartData(50, maxRange, BarChartType.VERTICAL, DataCategoryOptions())
|
||||
val yStepSize = 10
|
||||
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(barData.size - 1)
|
||||
.bottomPadding(40.dp)
|
||||
.axisLabelAngle(20f)
|
||||
.startDrawPadding(48.dp)
|
||||
.labelData { index -> barData[index].label }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val barChartData = BarChartData(
|
||||
chartData = barData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
barStyle = BarStyle(
|
||||
paddingBetweenBars = 20.dp,
|
||||
barWidth = 25.dp
|
||||
),
|
||||
showYAxis = true,
|
||||
showXAxis = true,
|
||||
horizontalExtraSpace = 10.dp,
|
||||
)
|
||||
BarChart(modifier = Modifier.height(350.dp), barChartData = barChartData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Barchart with gradient bars
|
||||
*
|
||||
*/
|
||||
@Composable
|
||||
private fun BarchartWithGradientBars() {
|
||||
val maxRange = 100
|
||||
val barData = DataUtils.getGradientBarChartData(50, 100)
|
||||
val yStepSize = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(barData.size - 1)
|
||||
.bottomPadding(40.dp)
|
||||
.axisLabelAngle(20f)
|
||||
.startDrawPadding(48.dp)
|
||||
.labelData { index -> barData[index].label }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val barChartData = BarChartData(
|
||||
chartData = barData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
barStyle = BarStyle(paddingBetweenBars = 20.dp,
|
||||
barWidth = 35.dp,
|
||||
isGradientEnabled = true,
|
||||
selectionHighlightData = SelectionHighlightData(
|
||||
highlightBarColor = Color.Red,
|
||||
highlightTextBackgroundColor = Color.Green,
|
||||
popUpLabel = { _, y -> " Value : $y " }
|
||||
)),
|
||||
showYAxis = true,
|
||||
showXAxis = true,
|
||||
horizontalExtraSpace = 20.dp
|
||||
)
|
||||
BarChart(modifier = Modifier.height(350.dp), barChartData = barChartData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Barchart with background color
|
||||
*
|
||||
*/
|
||||
@Composable
|
||||
private fun BarchartWithBackgroundColor() {
|
||||
val maxRange = 100
|
||||
val backgroundColor = Color.LightGray
|
||||
val barData = DataUtils.getBarChartData(50, 100, BarChartType.VERTICAL, DataCategoryOptions())
|
||||
val yStepSize = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(barData.size - 1)
|
||||
.bottomPadding(40.dp)
|
||||
.startDrawPadding(48.dp)
|
||||
.axisLabelAngle(20f)
|
||||
.labelData { index -> barData[index].label }
|
||||
.backgroundColor(backgroundColor)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.backgroundColor(backgroundColor)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val barChartData = BarChartData(
|
||||
chartData = barData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
barStyle = BarStyle(paddingBetweenBars = 20.dp,
|
||||
barWidth = 35.dp,
|
||||
selectionHighlightData = SelectionHighlightData(
|
||||
highlightBarColor = Color.Red,
|
||||
highlightTextBackgroundColor = Color.Green,
|
||||
popUpLabel = { _, y -> " Value : $y " }
|
||||
)),
|
||||
showYAxis = true,
|
||||
showXAxis = true,
|
||||
horizontalExtraSpace = 20.dp,
|
||||
backgroundColor = backgroundColor
|
||||
)
|
||||
BarChart(modifier = Modifier.height(350.dp), barChartData = barChartData)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun VerticalBarChart() {
|
||||
val maxRange = 50
|
||||
val barData =
|
||||
DataUtils.getBarChartData(50, maxRange, BarChartType.VERTICAL, DataCategoryOptions())
|
||||
val yStepSize = 10
|
||||
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(barData.size - 1)
|
||||
.bottomPadding(12.dp)
|
||||
.axisLabelAngle(20f)
|
||||
.startDrawPadding(48.dp)
|
||||
.shouldDrawAxisLineTillEnd(false)
|
||||
.labelData { index -> barData[index].label }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val barChartData = BarChartData(
|
||||
chartData = barData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
barStyle = BarStyle(
|
||||
paddingBetweenBars = 20.dp,
|
||||
barWidth = 25.dp
|
||||
),
|
||||
showYAxis = true,
|
||||
showXAxis = true,
|
||||
horizontalExtraSpace = 10.dp,
|
||||
drawBar = { drawScope, barData, drawOffset, height, barChartType, barStyle ->
|
||||
with(drawScope) {
|
||||
with(barStyle) {
|
||||
drawRect(
|
||||
color = barData.color,
|
||||
topLeft = drawOffset,
|
||||
size = if (barChartType == BarChartType.VERTICAL) Size(
|
||||
barWidth.toPx(),
|
||||
height
|
||||
) else Size(height, barWidth.toPx()),
|
||||
style = barDrawStyle,
|
||||
blendMode = barBlendMode
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
BarChart(modifier = Modifier.height(350.dp), barChartData = barChartData)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HorizontalBarChart() {
|
||||
val maxRange = 30
|
||||
val barData =
|
||||
DataUtils.getBarChartData(
|
||||
10,
|
||||
maxRange,
|
||||
BarChartType.HORIZONTAL,
|
||||
DataCategoryOptions(isDataCategoryInYAxis = true)
|
||||
)
|
||||
val xStepSize = 10
|
||||
|
||||
val xAxisData = AxisData.Builder()
|
||||
.steps(xStepSize)
|
||||
.bottomPadding(12.dp)
|
||||
.endPadding(40.dp)
|
||||
.labelData { index -> (index * (maxRange / xStepSize)).toString() }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(barData.size - 1)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.setDataCategoryOptions(
|
||||
DataCategoryOptions(
|
||||
isDataCategoryInYAxis = true,
|
||||
isDataCategoryStartFromBottom = false
|
||||
)
|
||||
)
|
||||
.startDrawPadding(48.dp)
|
||||
.labelData { index -> barData[index].label }
|
||||
.build()
|
||||
val barChartData = BarChartData(
|
||||
chartData = barData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
barStyle = BarStyle(
|
||||
isGradientEnabled = false,
|
||||
paddingBetweenBars = 20.dp,
|
||||
barWidth = 35.dp,
|
||||
selectionHighlightData = SelectionHighlightData(
|
||||
highlightBarColor = Color.Red,
|
||||
highlightTextBackgroundColor = Color.Green,
|
||||
popUpLabel = { x, _ -> " Value : $x " },
|
||||
barChartType = BarChartType.HORIZONTAL
|
||||
),
|
||||
),
|
||||
showYAxis = true,
|
||||
showXAxis = true,
|
||||
horizontalExtraSpace = 20.dp,
|
||||
barChartType = BarChartType.HORIZONTAL
|
||||
)
|
||||
BarChart(
|
||||
modifier = Modifier.height(350.dp),
|
||||
barChartData = barChartData
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun VerticalGroupBarChart() {
|
||||
val maxRange = 100
|
||||
val barSize = 3
|
||||
val groupBarData = DataUtils.getGroupBarChartData(50, maxRange, barSize)
|
||||
val yStepSize = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.bottomPadding(5.dp)
|
||||
.startDrawPadding(48.dp)
|
||||
.labelData { index -> index.toString() }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val colorPaletteList = DataUtils.getColorPaletteList(barSize)
|
||||
val legendsConfig = LegendsConfig(
|
||||
legendLabelList = DataUtils.getLegendsLabelData(colorPaletteList),
|
||||
gridColumnCount = 3
|
||||
)
|
||||
val groupBarPlotData = BarPlotData(
|
||||
groupBarList = groupBarData,
|
||||
barStyle = BarStyle(barWidth = 35.dp),
|
||||
barColorPaletteList = colorPaletteList
|
||||
)
|
||||
val groupBarChartData = GroupBarChartData(
|
||||
barPlotData = groupBarPlotData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
groupSeparatorConfig = GroupSeparatorConfig(0.dp)
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.height(450.dp)
|
||||
) {
|
||||
GroupBarChart(
|
||||
modifier = Modifier
|
||||
.height(400.dp),
|
||||
groupBarChartData = groupBarChartData
|
||||
)
|
||||
Legends(
|
||||
legendsConfig = legendsConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun VerticalStackedBarChart() {
|
||||
val barSize = 3
|
||||
val listSize = 10
|
||||
val groupBarData = DataUtils.getGroupBarChartData(listSize, 100, barSize)
|
||||
val yStepSize = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(listSize - 1)
|
||||
.startDrawPadding(48.dp)
|
||||
.labelData { index -> "C $index" }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index ->
|
||||
val valueList = mutableListOf<Float>()
|
||||
groupBarData.map { groupBar ->
|
||||
var yMax = 0f
|
||||
groupBar.barList.forEach {
|
||||
yMax += it.point.y
|
||||
}
|
||||
valueList.add(yMax)
|
||||
}
|
||||
val maxElementInYAxis = getMaxElementInYAxis(valueList.maxOrNull() ?: 0f, yStepSize)
|
||||
|
||||
(index * (maxElementInYAxis / yStepSize)).toString()
|
||||
}
|
||||
.topPadding(36.dp)
|
||||
.build()
|
||||
val colorPaletteList = DataUtils.getColorPaletteList(barSize)
|
||||
val legendsConfig = LegendsConfig(
|
||||
legendLabelList = DataUtils.getLegendsLabelData(colorPaletteList),
|
||||
gridColumnCount = 3
|
||||
)
|
||||
val groupBarPlotData = BarPlotData(
|
||||
groupBarList = groupBarData,
|
||||
barStyle = BarStyle(
|
||||
barWidth = 35.dp,
|
||||
selectionHighlightData = SelectionHighlightData(
|
||||
isHighlightFullBar = true,
|
||||
groupBarPopUpLabel = { name, value ->
|
||||
"Name : C$name Value : ${String.format("%.2f", value)}"
|
||||
}
|
||||
)
|
||||
),
|
||||
barColorPaletteList = colorPaletteList
|
||||
)
|
||||
val groupBarChartData = GroupBarChartData(
|
||||
barPlotData = groupBarPlotData,
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
paddingBetweenStackedBars = 4.dp,
|
||||
drawBar = { drawScope, barChartData, barStyle, drawOffset, height, barIndex ->
|
||||
with(drawScope) {
|
||||
drawRect(
|
||||
color = colorPaletteList[barIndex],
|
||||
topLeft = drawOffset,
|
||||
size = Size(barStyle.barWidth.toPx(), height),
|
||||
style = barStyle.barDrawStyle,
|
||||
blendMode = barStyle.barBlendMode
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.height(500.dp)
|
||||
) {
|
||||
StackedBarChart(
|
||||
modifier = Modifier
|
||||
.height(400.dp),
|
||||
groupBarChartData = groupBarChartData
|
||||
)
|
||||
Legends(
|
||||
legendsConfig = legendsConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.charts.axis.AxisData
|
||||
import co.yml.charts.common.extensions.formatToSinglePrecision
|
||||
import co.yml.charts.common.model.Point
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.bubblechart.BubbleChart
|
||||
import co.yml.charts.ui.bubblechart.model.BubbleChartData
|
||||
import co.yml.charts.ui.linechart.model.GridLines
|
||||
import co.yml.ycharts.app.R
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
/**
|
||||
* Line chart activity
|
||||
*
|
||||
* @constructor Create empty Line chart activity
|
||||
*/
|
||||
class BubbleChartActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.bubble_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
LazyColumn(content = {
|
||||
item {
|
||||
Text(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
text = getString(R.string.gradient_bubble_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
BubbleChartWithGrid(
|
||||
pointsData = DataUtils.getRandomPoints(
|
||||
200,
|
||||
start = 30,
|
||||
maxRange = 100
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
}
|
||||
|
||||
item {
|
||||
Text(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
text = getString(R.string.solid_bubble_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
SolidBubbleChart(
|
||||
pointsData = DataUtils.getRandomPoints(
|
||||
200,
|
||||
start = 30,
|
||||
maxRange = 900
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bubble chart with grid lines
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun BubbleChartWithGrid(pointsData: List<Point>) {
|
||||
val steps = 5
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> pointsData[i].x.toInt().toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.build()
|
||||
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}.build()
|
||||
|
||||
val data = BubbleChartData(
|
||||
DataUtils.getBubbleChartDataWithGradientStyle(pointsData),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
gridLines = GridLines()
|
||||
)
|
||||
|
||||
BubbleChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(500.dp),
|
||||
bubbleChartData = data
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bubble chart with grid lines
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun SolidBubbleChart(pointsData: List<Point>) {
|
||||
val steps = 5
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i ->pointsData[i].x.toInt().toString()}
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.build()
|
||||
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}.build()
|
||||
|
||||
val data = BubbleChartData(
|
||||
DataUtils.getBubbleChartDataWithSolidStyle(pointsData),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
gridLines = GridLines()
|
||||
)
|
||||
|
||||
BubbleChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(500.dp),
|
||||
bubbleChartData = data
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
@file:OptIn(ExperimentalMaterialApi::class)
|
||||
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.charts.axis.AxisData
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
import co.yml.charts.ui.barchart.models.BarPlotData
|
||||
import co.yml.charts.ui.barchart.models.BarStyle
|
||||
import co.yml.charts.ui.combinedchart.CombinedChart
|
||||
import co.yml.charts.ui.combinedchart.model.CombinedChartData
|
||||
import co.yml.charts.common.components.Legends
|
||||
import co.yml.charts.common.model.LegendsConfig
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.linechart.model.IntersectionPoint
|
||||
import co.yml.charts.ui.linechart.model.Line
|
||||
import co.yml.charts.ui.linechart.model.LinePlotData
|
||||
import co.yml.charts.ui.linechart.model.LineStyle
|
||||
import co.yml.charts.ui.linechart.model.SelectionHighlightPoint
|
||||
import co.yml.charts.ui.linechart.model.SelectionHighlightPopUp
|
||||
import co.yml.ycharts.app.R
|
||||
|
||||
/**
|
||||
* Combined line and bar chart activity
|
||||
*
|
||||
* @constructor Create empty Combined line and bar chart activity
|
||||
*/
|
||||
class CombinedLineAndBarChartActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.title_bar_with_line_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
LazyColumn(content = {
|
||||
items(2) { item ->
|
||||
when (item) {
|
||||
0 ->{
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.combined_bar_line_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
BarWithLineChart()
|
||||
}
|
||||
1->{
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.combined_chart_with_background),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
BarWithLineChartAndBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bar with line chart
|
||||
*
|
||||
*/
|
||||
@Composable
|
||||
fun BarWithLineChart() {
|
||||
val maxRange = 100
|
||||
val groupBarData = DataUtils.getGroupBarChartData(50, 100, 3)
|
||||
val yStepSize = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.bottomPadding(5.dp)
|
||||
.labelData { index -> index.toString() }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
DataUtils.getLineChartData(50, maxRange = 100),
|
||||
lineStyle = LineStyle(color = Color.Blue),
|
||||
intersectionPoint = IntersectionPoint(),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp()
|
||||
),
|
||||
Line(
|
||||
DataUtils.getLineChartData(50, maxRange = 100),
|
||||
lineStyle = LineStyle(color = Color.Black),
|
||||
intersectionPoint = IntersectionPoint(),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp()
|
||||
)
|
||||
)
|
||||
)
|
||||
val colorPaletteList = DataUtils.getColorPaletteList(3)
|
||||
val legendsConfig = LegendsConfig(
|
||||
legendLabelList = DataUtils.getLegendsLabelData(colorPaletteList),
|
||||
gridColumnCount = 3
|
||||
)
|
||||
val barPlotData = BarPlotData(
|
||||
groupBarList = groupBarData,
|
||||
barStyle = BarStyle(barWidth = 35.dp),
|
||||
barColorPaletteList = colorPaletteList
|
||||
)
|
||||
val combinedChartData = CombinedChartData(
|
||||
combinedPlotDataList = listOf(barPlotData, linePlotData),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.height(500.dp)
|
||||
) {
|
||||
CombinedChart(
|
||||
modifier = Modifier
|
||||
.height(400.dp),
|
||||
combinedChartData = combinedChartData
|
||||
)
|
||||
Legends(
|
||||
legendsConfig = legendsConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bar with line chart and background
|
||||
*
|
||||
*/
|
||||
@Composable
|
||||
fun BarWithLineChartAndBackground() {
|
||||
val maxRange = 100
|
||||
val groupBarData = DataUtils.getGroupBarChartData(50, 100, 3)
|
||||
val yStepSize = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.bottomPadding(5.dp)
|
||||
.backgroundColor(Color.Yellow)
|
||||
.labelData { index -> index.toString() }
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(yStepSize)
|
||||
.backgroundColor(Color.Yellow)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.axisOffset(20.dp)
|
||||
.labelData { index -> (index * (maxRange / yStepSize)).toString() }
|
||||
.build()
|
||||
val linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
DataUtils.getLineChartData(50, maxRange = 100),
|
||||
lineStyle = LineStyle(color = Color.Blue),
|
||||
intersectionPoint = IntersectionPoint(),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp()
|
||||
),
|
||||
Line(
|
||||
DataUtils.getLineChartData(50, maxRange = 100),
|
||||
lineStyle = LineStyle(color = Color.Black),
|
||||
intersectionPoint = IntersectionPoint(),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp()
|
||||
)
|
||||
)
|
||||
)
|
||||
val colorPaletteList = DataUtils.getColorPaletteList(3)
|
||||
val legendsConfig = LegendsConfig(
|
||||
legendLabelList = DataUtils.getLegendsLabelData(colorPaletteList),
|
||||
gridColumnCount = 3
|
||||
)
|
||||
val barPlotData = BarPlotData(
|
||||
groupBarList = groupBarData,
|
||||
barStyle = BarStyle(barWidth = 35.dp),
|
||||
barColorPaletteList = colorPaletteList
|
||||
)
|
||||
val combinedChartData = CombinedChartData(
|
||||
combinedPlotDataList = listOf(barPlotData, linePlotData),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
backgroundColor = Color.Yellow
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.height(500.dp)
|
||||
) {
|
||||
CombinedChart(
|
||||
modifier = Modifier
|
||||
.height(400.dp),
|
||||
combinedChartData = combinedChartData
|
||||
)
|
||||
Legends(
|
||||
legendsConfig = legendsConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import co.yml.charts.common.components.Legends
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.piechart.charts.DonutPieChart
|
||||
import co.yml.charts.ui.piechart.models.PieChartConfig
|
||||
import co.yml.charts.ui.piechart.utils.proportion
|
||||
import co.yml.ycharts.app.R
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
/**
|
||||
* Donut chart activity
|
||||
*
|
||||
* @constructor Create empty Donut chart activity
|
||||
*/
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
class DonutChartActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.title_donut_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
val context = LocalContext.current
|
||||
LazyColumn(content = {
|
||||
items(2) { item ->
|
||||
when (item) {
|
||||
0 -> {
|
||||
Text(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
text = getString(R.string.simple_donut_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(it)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
SimpleDonutChart(context)
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
Text(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
text = getString(R.string.multiple_donuts),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
MultipleSmallDonutCharts(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple donut chart
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
private fun SimpleDonutChart(context: Context) {
|
||||
val accessibilitySheetState =
|
||||
rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
|
||||
val scope = rememberCoroutineScope()
|
||||
val data = DataUtils.getDonutChartData()
|
||||
// Sum of all the values
|
||||
val sumOfValues = data.totalLength
|
||||
|
||||
// Calculate each proportion value
|
||||
val proportions = data.slices.proportion(sumOfValues)
|
||||
val pieChartConfig =
|
||||
PieChartConfig(
|
||||
labelVisible = true,
|
||||
strokeWidth = 120f,
|
||||
labelColor = Color.Black,
|
||||
activeSliceAlpha = .9f,
|
||||
isEllipsizeEnabled = true,
|
||||
labelTypeface = Typeface.defaultFromStyle(Typeface.BOLD),
|
||||
isAnimationEnable = true,
|
||||
chartPadding = 25,
|
||||
labelFontSize = 42.sp,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(500.dp)
|
||||
) {
|
||||
Legends(legendsConfig = DataUtils.getLegendsConfigFromPieChartData(pieChartData = data, 3))
|
||||
DonutPieChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp),
|
||||
data,
|
||||
pieChartConfig
|
||||
) { slice ->
|
||||
Toast.makeText(context, slice.label, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple small donut charts
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
private fun MultipleSmallDonutCharts(context: Context) {
|
||||
val accessibilitySheetState =
|
||||
rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
|
||||
val scope = rememberCoroutineScope()
|
||||
val data = DataUtils.getDonutChartData()
|
||||
// Sum of all the values
|
||||
val sumOfValues = data.totalLength
|
||||
|
||||
// Calculate each proportion value
|
||||
val proportions = data.slices.proportion(sumOfValues)
|
||||
val firstPieChartConfig =
|
||||
PieChartConfig(
|
||||
labelVisible = true,
|
||||
strokeWidth = 50f,
|
||||
labelColor = Color.Black,
|
||||
backgroundColor = Color.Yellow,
|
||||
activeSliceAlpha = .9f,
|
||||
isEllipsizeEnabled = true,
|
||||
labelTypeface = Typeface.defaultFromStyle(Typeface.BOLD),
|
||||
isAnimationEnable = true,
|
||||
chartPadding = 25,
|
||||
labelFontSize = 16.sp
|
||||
)
|
||||
val secondPieChartConfig =
|
||||
PieChartConfig(
|
||||
labelVisible = true,
|
||||
strokeWidth = 50f,
|
||||
labelColor = Color.Black,
|
||||
activeSliceAlpha = .9f,
|
||||
isEllipsizeEnabled = true,
|
||||
backgroundColor = Color.Black,
|
||||
labelTypeface = Typeface.defaultFromStyle(Typeface.BOLD),
|
||||
isAnimationEnable = true,
|
||||
chartPadding = 25,
|
||||
labelFontSize = 16.sp,
|
||||
isSumVisible = true,
|
||||
sumUnit = "unit",
|
||||
labelColorType = PieChartConfig.LabelColorType.SLICE_COLOR,
|
||||
labelType = PieChartConfig.LabelType.VALUE
|
||||
)
|
||||
val thirdPieChartConfig =
|
||||
PieChartConfig(
|
||||
labelVisible = true,
|
||||
strokeWidth = 50f,
|
||||
labelColor = Color.Black,
|
||||
activeSliceAlpha = .9f,
|
||||
backgroundColor = Color.LightGray,
|
||||
isEllipsizeEnabled = true,
|
||||
labelTypeface = Typeface.defaultFromStyle(Typeface.BOLD),
|
||||
isAnimationEnable = true,
|
||||
chartPadding = 25,
|
||||
labelFontSize = 16.sp
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp)
|
||||
) {
|
||||
Legends(legendsConfig = DataUtils.getLegendsConfigFromPieChartData(pieChartData = data, 3))
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
LazyRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
item {
|
||||
DonutPieChart(
|
||||
modifier = Modifier
|
||||
.width(100.dp)
|
||||
.height(100.dp),
|
||||
data,
|
||||
firstPieChartConfig
|
||||
) { slice ->
|
||||
Toast.makeText(context, slice.label, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
Spacer(modifier = Modifier.width(30.dp))
|
||||
}
|
||||
item {
|
||||
DonutPieChart(
|
||||
modifier = Modifier
|
||||
.width(100.dp)
|
||||
.height(100.dp),
|
||||
data,
|
||||
secondPieChartConfig
|
||||
) { slice ->
|
||||
Toast.makeText(context, slice.label, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
Spacer(modifier = Modifier.width(30.dp))
|
||||
}
|
||||
item {
|
||||
DonutPieChart(
|
||||
modifier = Modifier
|
||||
.width(100.dp)
|
||||
.height(100.dp),
|
||||
data,
|
||||
thirdPieChartConfig
|
||||
) { slice ->
|
||||
Toast.makeText(context, slice.label, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
Spacer(modifier = Modifier.width(30.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,642 @@
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.charts.axis.AxisData
|
||||
import co.yml.charts.common.components.Legends
|
||||
import co.yml.charts.common.extensions.formatToSinglePrecision
|
||||
import co.yml.charts.common.model.LegendsConfig
|
||||
import co.yml.charts.common.model.Point
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.linechart.LineChart
|
||||
import co.yml.charts.ui.linechart.model.GridLines
|
||||
import co.yml.charts.ui.linechart.model.IntersectionPoint
|
||||
import co.yml.charts.ui.linechart.model.Line
|
||||
import co.yml.charts.ui.linechart.model.LineChartData
|
||||
import co.yml.charts.ui.linechart.model.LinePlotData
|
||||
import co.yml.charts.ui.linechart.model.LineStyle
|
||||
import co.yml.charts.ui.linechart.model.LineType
|
||||
import co.yml.charts.ui.linechart.model.SelectionHighlightPoint
|
||||
import co.yml.charts.ui.linechart.model.SelectionHighlightPopUp
|
||||
import co.yml.charts.ui.linechart.model.ShadowUnderLine
|
||||
import co.yml.ycharts.app.R
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
/**
|
||||
* Line chart activity
|
||||
*
|
||||
* @constructor Create empty Line chart activity
|
||||
*/
|
||||
class LineChartActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.title_line_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
LazyColumn(content = {
|
||||
item {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.linechart_default_style),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
SingleLineChartWithGridLines(
|
||||
DataUtils.getLineChartData(
|
||||
100,
|
||||
start = 50,
|
||||
maxRange = 100
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Divider(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp))
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.linechart_straight_line_style),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
StraightLinechart(DataUtils.getLineChartData(50, maxRange = 200))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Divider(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp))
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.linechart_dotted_style),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
DottedLinechart(DataUtils.getLineChartData(
|
||||
200,
|
||||
start = -50,
|
||||
maxRange = 50
|
||||
))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Divider(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp))
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.linechart_multiple_tones),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
MultipleToneLinechart(DataUtils.getLineChartData(
|
||||
200,
|
||||
start = -50,
|
||||
maxRange = 50
|
||||
))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Divider(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp))
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.combined_line_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
CombinedLinechart(DataUtils.getLineChartData(
|
||||
200,
|
||||
start = -50,
|
||||
maxRange = 50
|
||||
))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Divider(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp))
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.combined_line_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
CombinedLinechartWithBackground(DataUtils.getLineChartData(
|
||||
200,
|
||||
start = -50,
|
||||
maxRange = 50
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single line chart with grid lines
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun SingleLineChartWithGridLines(pointsData: List<Point>) {
|
||||
val steps = 5
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.topPadding(105.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> pointsData[i].x.toInt().toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}.build()
|
||||
val data = LineChartData(
|
||||
linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
dataPoints = pointsData,
|
||||
LineStyle(),
|
||||
IntersectionPoint(),
|
||||
SelectionHighlightPoint(),
|
||||
ShadowUnderLine(),
|
||||
SelectionHighlightPopUp()
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
gridLines = GridLines()
|
||||
)
|
||||
LineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
lineChartData = data
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Straight linechart
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun StraightLinechart(pointsData: List<Point>) {
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(40.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> (1900 + i).toString() }
|
||||
.axisLabelAngle(20f)
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.axisLabelColor(Color.Blue)
|
||||
.axisLineColor(Color.DarkGray)
|
||||
.typeFace(Typeface.DEFAULT_BOLD)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(10)
|
||||
.labelData { i -> "${(i * 20)}k" }
|
||||
.labelAndAxisLinePadding(30.dp)
|
||||
.axisLabelColor(Color.Blue)
|
||||
.axisLineColor(Color.DarkGray)
|
||||
.typeFace(Typeface.DEFAULT_BOLD)
|
||||
.build()
|
||||
val data = LineChartData(
|
||||
linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
dataPoints = pointsData,
|
||||
lineStyle = LineStyle(lineType = LineType.Straight(), color = Color.Blue),
|
||||
intersectionPoint = IntersectionPoint(color = Color.Red),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData
|
||||
)
|
||||
LineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
lineChartData = data
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple tone linechart
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun MultipleToneLinechart(pointsData: List<Point>) {
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(40.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> (1900 + i).toString() }
|
||||
.axisLabelAngle(20f)
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.axisLabelColor(Color.Blue)
|
||||
.axisLineColor(Color.DarkGray)
|
||||
.typeFace(Typeface.DEFAULT_BOLD)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(10)
|
||||
.labelData { i -> "${(i * 20)}k" }
|
||||
.labelAndAxisLinePadding(30.dp)
|
||||
.axisLabelColor(Color.Blue)
|
||||
.axisLineColor(Color.DarkGray)
|
||||
.typeFace(Typeface.DEFAULT_BOLD)
|
||||
.build()
|
||||
val data = LineChartData(
|
||||
linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
dataPoints = pointsData,
|
||||
lineStyle = LineStyle(lineType = LineType.Straight(), color = Color.Blue),
|
||||
intersectionPoint = IntersectionPoint(color = Color.Red),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
), Line(
|
||||
dataPoints = pointsData.subList(0, 10),
|
||||
lineStyle = LineStyle(lineType = LineType.Straight(), color = Color.Magenta),
|
||||
intersectionPoint = IntersectionPoint(color = Color.Red),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
), Line(
|
||||
dataPoints = pointsData.subList(15, 30),
|
||||
lineStyle = LineStyle(lineType = LineType.Straight(), color = Color.Yellow),
|
||||
intersectionPoint = IntersectionPoint(color = Color.Red),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData
|
||||
)
|
||||
LineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
lineChartData = data
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dotted linechart
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun DottedLinechart(pointsData: List<Point>) {
|
||||
val steps = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(40.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> i.toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.axisLineColor(Color.Red)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelData { i ->
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}
|
||||
.axisLineColor(Color.Red)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.build()
|
||||
val data = LineChartData(
|
||||
linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
dataPoints = pointsData,
|
||||
lineStyle = LineStyle(
|
||||
lineType = LineType.SmoothCurve(isDotted = true),
|
||||
color = Color.Green
|
||||
),
|
||||
shadowUnderLine = ShadowUnderLine(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Green,
|
||||
Color.Transparent
|
||||
)
|
||||
), alpha = 0.3f
|
||||
),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(
|
||||
color = Color.Green
|
||||
),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(
|
||||
backgroundColor = Color.Black,
|
||||
backgroundStyle = Stroke(2f),
|
||||
labelColor = Color.Red,
|
||||
labelTypeface = Typeface.DEFAULT_BOLD
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData
|
||||
)
|
||||
LineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
lineChartData = data
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined linechart
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun CombinedLinechart(pointsData: List<Point>) {
|
||||
val steps = 5
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> i.toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}.build()
|
||||
val colorPaletteList = listOf<Color>(Color.Blue,Color.Yellow,Color.Magenta,Color.DarkGray)
|
||||
val legendsConfig = LegendsConfig(
|
||||
legendLabelList = DataUtils.getLegendsLabelData(colorPaletteList),
|
||||
gridColumnCount = 4
|
||||
)
|
||||
val data = LineChartData(
|
||||
linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
dataPoints = pointsData,
|
||||
lineStyle = LineStyle(
|
||||
lineType = LineType.SmoothCurve(isDotted = true),
|
||||
color = colorPaletteList.first()
|
||||
),
|
||||
shadowUnderLine = ShadowUnderLine(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Green,
|
||||
Color.Transparent
|
||||
)
|
||||
), alpha = 0.3f
|
||||
),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(
|
||||
color = Color.Green
|
||||
),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(
|
||||
backgroundColor = Color.Black,
|
||||
backgroundStyle = Stroke(2f),
|
||||
labelColor = Color.Red,
|
||||
labelTypeface = Typeface.DEFAULT_BOLD
|
||||
)
|
||||
),
|
||||
Line(
|
||||
dataPoints = pointsData.subList(10,20),
|
||||
lineStyle = LineStyle(lineType = LineType.SmoothCurve(), color = colorPaletteList[1]),
|
||||
intersectionPoint = IntersectionPoint(color = Color.Red),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
),
|
||||
Line(
|
||||
dataPoints = DataUtils.getLineChartData(
|
||||
20,
|
||||
start = 0,
|
||||
maxRange = 50
|
||||
),
|
||||
LineStyle(color = colorPaletteList[2]),
|
||||
IntersectionPoint(),
|
||||
SelectionHighlightPoint(),
|
||||
shadowUnderLine = ShadowUnderLine(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Cyan,
|
||||
Color.Blue
|
||||
)
|
||||
), alpha = 0.5f
|
||||
),
|
||||
SelectionHighlightPopUp()
|
||||
),
|
||||
Line(
|
||||
dataPoints = pointsData.subList(10, 20),
|
||||
LineStyle(color = colorPaletteList[3]),
|
||||
IntersectionPoint(),
|
||||
SelectionHighlightPoint(),
|
||||
ShadowUnderLine(),
|
||||
SelectionHighlightPopUp()
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
gridLines = GridLines()
|
||||
)
|
||||
|
||||
Column(modifier = Modifier.height(400.dp)) {
|
||||
LineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
lineChartData = data
|
||||
)
|
||||
Legends(
|
||||
legendsConfig = legendsConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined linechart with background
|
||||
*
|
||||
* @param pointsData
|
||||
*/
|
||||
@Composable
|
||||
private fun CombinedLinechartWithBackground(pointsData: List<Point>) {
|
||||
val steps = 5
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.backgroundColor(Color.Yellow)
|
||||
.labelData { i -> i.toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.backgroundColor(Color.Yellow)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}.build()
|
||||
val colorPaletteList = listOf<Color>(Color.Blue,Color.Yellow,Color.Magenta,Color.DarkGray)
|
||||
val legendsConfig = LegendsConfig(
|
||||
legendLabelList = DataUtils.getLegendsLabelData(colorPaletteList),
|
||||
gridColumnCount = 4
|
||||
)
|
||||
val data = LineChartData(
|
||||
linePlotData = LinePlotData(
|
||||
lines = listOf(
|
||||
Line(
|
||||
dataPoints = pointsData,
|
||||
lineStyle = LineStyle(
|
||||
lineType = LineType.SmoothCurve(isDotted = true),
|
||||
color = colorPaletteList.first()
|
||||
),
|
||||
shadowUnderLine = ShadowUnderLine(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Green,
|
||||
Color.Transparent
|
||||
)
|
||||
), alpha = 0.3f
|
||||
),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(
|
||||
color = Color.Green
|
||||
),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(
|
||||
backgroundColor = Color.Black,
|
||||
backgroundStyle = Stroke(2f),
|
||||
labelColor = Color.Red,
|
||||
labelTypeface = Typeface.DEFAULT_BOLD
|
||||
)
|
||||
),
|
||||
Line(
|
||||
dataPoints = pointsData.subList(10,20),
|
||||
lineStyle = LineStyle(lineType = LineType.SmoothCurve(), color = colorPaletteList[1]),
|
||||
intersectionPoint = IntersectionPoint(color = Color.Red),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
),
|
||||
Line(
|
||||
dataPoints = DataUtils.getLineChartData(
|
||||
20,
|
||||
start = 0,
|
||||
maxRange = 50
|
||||
),
|
||||
LineStyle(color = colorPaletteList[2]),
|
||||
IntersectionPoint(),
|
||||
SelectionHighlightPoint(),
|
||||
shadowUnderLine = ShadowUnderLine(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Cyan,
|
||||
Color.Blue
|
||||
)
|
||||
), alpha = 0.5f
|
||||
),
|
||||
SelectionHighlightPopUp()
|
||||
),
|
||||
Line(
|
||||
dataPoints = pointsData.subList(10, 20),
|
||||
LineStyle(color = colorPaletteList[3]),
|
||||
IntersectionPoint(),
|
||||
SelectionHighlightPoint(),
|
||||
ShadowUnderLine(),
|
||||
SelectionHighlightPopUp()
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
gridLines = GridLines(),
|
||||
backgroundColor = Color.Yellow
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.height(400.dp)
|
||||
) {
|
||||
LineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
lineChartData = data
|
||||
)
|
||||
Legends(
|
||||
legendsConfig = legendsConfig
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.charts.common.components.Legends
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.piechart.charts.PieChart
|
||||
import co.yml.charts.ui.piechart.models.PieChartConfig
|
||||
import co.yml.ycharts.app.R
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
/**
|
||||
* Pie chart activity
|
||||
*
|
||||
* @constructor Create empty Pie chart activity
|
||||
*/
|
||||
class PieChartActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.title_pie_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
LazyColumn(content = {
|
||||
items(3) { item ->
|
||||
when (item) {
|
||||
0 -> {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.simple_piechart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
SimplePiechart(LocalContext.current)
|
||||
}
|
||||
1 -> {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.piechart_with_lables),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
PiechartWithSliceLables(LocalContext.current)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple piechart
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@Composable
|
||||
private fun SimplePiechart(context: Context) {
|
||||
val pieChartData = DataUtils.getPieChartData()
|
||||
val pieChartConfig =
|
||||
PieChartConfig(
|
||||
labelVisible = true,
|
||||
activeSliceAlpha = .9f,
|
||||
isEllipsizeEnabled = true,
|
||||
sliceLabelEllipsizeAt = TextUtils.TruncateAt.MIDDLE,
|
||||
isAnimationEnable = true,
|
||||
chartPadding = 30,
|
||||
backgroundColor = Color.Black,
|
||||
showSliceLabels = false,
|
||||
animationDuration = 1500
|
||||
)
|
||||
Column(modifier = Modifier.height(500.dp)) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Legends(legendsConfig = DataUtils.getLegendsConfigFromPieChartData(pieChartData, 3))
|
||||
PieChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp),
|
||||
pieChartData,
|
||||
pieChartConfig
|
||||
) { slice ->
|
||||
Toast.makeText(context, slice.label, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Piechart with slice lables
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@Composable
|
||||
private fun PiechartWithSliceLables(context: Context) {
|
||||
val pieChartData = DataUtils.getPieChartData2()
|
||||
|
||||
val pieChartConfig =
|
||||
PieChartConfig(
|
||||
activeSliceAlpha = .9f,
|
||||
isEllipsizeEnabled = true,
|
||||
sliceLabelEllipsizeAt = TextUtils.TruncateAt.MIDDLE,
|
||||
sliceLabelTypeface = Typeface.defaultFromStyle(Typeface.ITALIC),
|
||||
isAnimationEnable = true,
|
||||
chartPadding = 20,
|
||||
showSliceLabels = true,
|
||||
labelVisible = true
|
||||
)
|
||||
Column(modifier = Modifier.height(500.dp)) {
|
||||
Legends(legendsConfig = DataUtils.getLegendsConfigFromPieChartData(pieChartData, 3))
|
||||
PieChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(400.dp),
|
||||
pieChartData,
|
||||
pieChartConfig
|
||||
) { slice ->
|
||||
Toast.makeText(context, slice.label, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
package co.yml.ycharts.app.presentation
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.charts.axis.AxisData
|
||||
import co.yml.charts.common.extensions.formatToSinglePrecision
|
||||
import co.yml.charts.common.model.Point
|
||||
import co.yml.charts.common.utils.DataUtils
|
||||
import co.yml.charts.ui.linechart.model.*
|
||||
import co.yml.charts.ui.wavechart.WaveChart
|
||||
import co.yml.charts.ui.wavechart.model.Wave
|
||||
import co.yml.charts.ui.wavechart.model.WaveChartData
|
||||
import co.yml.charts.ui.wavechart.model.WaveFillColor
|
||||
import co.yml.charts.ui.wavechart.model.WavePlotData
|
||||
import co.yml.ycharts.app.R
|
||||
import co.yml.ycharts.app.ui.compositions.AppBarWithBackButton
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
class WaveChartActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
YChartsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor = YChartsTheme.colors.background,
|
||||
topBar = {
|
||||
AppBarWithBackButton(
|
||||
stringResource(id = R.string.title_wave_chart),
|
||||
onBackPressed = {
|
||||
onBackPressed()
|
||||
})
|
||||
})
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
LazyColumn(content = {
|
||||
items(3) { item ->
|
||||
when (item) {
|
||||
0 -> {
|
||||
Text(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
text = getString(R.string.simple_wave_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
WaveGraph1(
|
||||
DataUtils.getWaveChartData(
|
||||
15.0,
|
||||
50.0,
|
||||
0.5
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
1 -> {
|
||||
Text(
|
||||
modifier=Modifier.padding(12.dp),
|
||||
text = getString(R.string.sine_wave_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
WaveGraph2(
|
||||
DataUtils.getWaveChartData(
|
||||
15.0,
|
||||
50.0,
|
||||
0.2
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
Text(
|
||||
modifier = Modifier.padding(12.dp),
|
||||
text = getString(R.string.amplitude_wave_chart),
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
WaveGraph3(
|
||||
DataUtils.getWaveChartData(
|
||||
20.0,
|
||||
5.0,
|
||||
1.0
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WaveGraph1(pointsData: List<Point>) {
|
||||
val steps = 5
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(30.dp)
|
||||
.startDrawPadding(48.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> i.toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}.build()
|
||||
val data = WaveChartData(
|
||||
wavePlotData = WavePlotData(
|
||||
lines = listOf(
|
||||
Wave(
|
||||
dataPoints = pointsData,
|
||||
waveStyle = LineStyle(color = Color.Black),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(),
|
||||
shadowUnderLine = ShadowUnderLine(),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(),
|
||||
waveFillColor = WaveFillColor(topColor = Color.Green, bottomColor = Color.Red),
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData,
|
||||
gridLines = GridLines()
|
||||
)
|
||||
WaveChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
waveChartData = data
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WaveGraph2(pointsData: List<Point>) {
|
||||
val steps = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(40.dp)
|
||||
.startDrawPadding(48.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> (i).toString() }
|
||||
.axisLabelAngle(20f)
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.axisLabelColor(Color.Blue)
|
||||
.axisLineColor(Color.DarkGray)
|
||||
.typeFace(Typeface.DEFAULT_BOLD)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(10)
|
||||
.labelData { i ->
|
||||
// Add yMin to get the negative axis values to the scale
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}
|
||||
.labelAndAxisLinePadding(30.dp)
|
||||
.axisLabelColor(Color.Blue)
|
||||
.axisLineColor(Color.DarkGray)
|
||||
.typeFace(Typeface.DEFAULT_BOLD)
|
||||
.build()
|
||||
val data = WaveChartData(
|
||||
wavePlotData = WavePlotData(
|
||||
lines = listOf(
|
||||
Wave(
|
||||
dataPoints = pointsData,
|
||||
waveStyle = LineStyle(lineType = LineType.SmoothCurve(), color = Color.Blue),
|
||||
shadowUnderLine = ShadowUnderLine(alpha = 0.5f),
|
||||
waveFillColor = WaveFillColor(
|
||||
topColor = Color.Yellow,
|
||||
bottomColor = Color.Magenta
|
||||
),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(popUpLabel = { x, y ->
|
||||
val xLabel = "x : ${(1900 + x).toInt()} "
|
||||
val yLabel = "y : ${String.format("%.2f", y)}"
|
||||
"$xLabel $yLabel"
|
||||
})
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData
|
||||
)
|
||||
WaveChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
waveChartData = data
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WaveGraph3(pointsData: List<Point>) {
|
||||
val steps = 10
|
||||
val xAxisData = AxisData.Builder()
|
||||
.axisStepSize(40.dp)
|
||||
.startDrawPadding(48.dp)
|
||||
.steps(pointsData.size - 1)
|
||||
.labelData { i -> i.toString() }
|
||||
.labelAndAxisLinePadding(15.dp)
|
||||
.axisLineColor(Color.Red)
|
||||
.build()
|
||||
val yAxisData = AxisData.Builder()
|
||||
.steps(steps)
|
||||
.labelData { i ->
|
||||
val yMin = pointsData.minOf { it.y }
|
||||
val yMax = pointsData.maxOf { it.y }
|
||||
val yScale = (yMax - yMin) / steps
|
||||
((i * yScale) + yMin).formatToSinglePrecision()
|
||||
}
|
||||
.axisLineColor(Color.Red)
|
||||
.labelAndAxisLinePadding(20.dp)
|
||||
.bottomPadding(15.dp)
|
||||
.build()
|
||||
val data = WaveChartData(
|
||||
wavePlotData = WavePlotData(
|
||||
lines = listOf(
|
||||
Wave(
|
||||
dataPoints = pointsData,
|
||||
waveStyle = LineStyle(
|
||||
lineType = LineType.Straight(isDotted = true),
|
||||
color = Color.Green
|
||||
),
|
||||
shadowUnderLine = ShadowUnderLine(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Green,
|
||||
Color.Transparent
|
||||
)
|
||||
), alpha = 0.3f
|
||||
),
|
||||
selectionHighlightPoint = SelectionHighlightPoint(
|
||||
color = Color.Green
|
||||
),
|
||||
selectionHighlightPopUp = SelectionHighlightPopUp(
|
||||
backgroundColor = Color.Black,
|
||||
backgroundStyle = Stroke(2f),
|
||||
labelColor = Color.Red,
|
||||
labelTypeface = Typeface.DEFAULT_BOLD
|
||||
),
|
||||
waveFillColor = WaveFillColor(
|
||||
topColor = Color.Green,
|
||||
bottomColor = Color.Red,
|
||||
topBrush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Green,
|
||||
Color.Blue
|
||||
)
|
||||
),
|
||||
bottomBrush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Green,
|
||||
Color.Red
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
xAxisData = xAxisData,
|
||||
yAxisData = yAxisData
|
||||
)
|
||||
WaveChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
waveChartData = data
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package co.yml.ycharts.app.ui.compositions
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.yml.ycharts.app.R
|
||||
import co.yml.ycharts.app.ui.theme.YChartsTheme
|
||||
|
||||
@Composable
|
||||
fun AppBarWithBackButton(title: String, onBackPressed: () -> Unit) {
|
||||
TopAppBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(60.dp),
|
||||
backgroundColor = YChartsTheme.colors.button,
|
||||
elevation = 6.dp,
|
||||
content = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Start
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(5.dp))
|
||||
IconButton(
|
||||
onClick = { onBackPressed() },
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_back_arrow),
|
||||
contentDescription = "Back",
|
||||
tint = Color.Unspecified
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = title,
|
||||
color = YChartsTheme.colors.text,
|
||||
textAlign = TextAlign.Center,
|
||||
style = YChartsTheme.typography.header
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package co.yml.ycharts.app.ui.theme
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
class YChartsColors(
|
||||
background: Color,
|
||||
primary: Color,
|
||||
text: Color,
|
||||
button: Color
|
||||
) {
|
||||
|
||||
var background by mutableStateOf(background)
|
||||
private set
|
||||
var primary by mutableStateOf(primary)
|
||||
private set
|
||||
var text by mutableStateOf(text)
|
||||
private set
|
||||
var button by mutableStateOf(button)
|
||||
private set
|
||||
}
|
||||
|
||||
fun lightColors(
|
||||
background: Color = Color.White,
|
||||
primary: Color = Color.White,
|
||||
text: Color = Color.White,
|
||||
button: Color = DarkGrey
|
||||
): YChartsColors = YChartsColors(
|
||||
background,
|
||||
primary,
|
||||
text,
|
||||
button
|
||||
)
|
||||
|
||||
fun darkColors(
|
||||
background: Color = DarkGrey,
|
||||
primary: Color = DarkGrey,
|
||||
text: Color = DarkGrey,
|
||||
button: Color = Color.White
|
||||
): YChartsColors = YChartsColors(
|
||||
background,
|
||||
primary,
|
||||
text,
|
||||
button
|
||||
)
|
||||
|
||||
val DarkGrey = Color(0xFF0F0F0F)
|
||||
|
||||
val LocalColors = staticCompositionLocalOf { lightColors() }
|
||||
@@ -0,0 +1,13 @@
|
||||
package co.yml.ycharts.app.ui.theme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
data class YChartsShapes(
|
||||
val small: RoundedCornerShape = RoundedCornerShape(4.dp),
|
||||
val medium: RoundedCornerShape = RoundedCornerShape(8.dp),
|
||||
val large: RoundedCornerShape = RoundedCornerShape(0.dp)
|
||||
)
|
||||
|
||||
internal val LocalShapes = staticCompositionLocalOf { YChartsShapes() }
|
||||
@@ -0,0 +1,56 @@
|
||||
package co.yml.ycharts.app.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
private val DarkColorPalette = darkColors(
|
||||
background = DarkGrey,
|
||||
primary = DarkGrey,
|
||||
text = DarkGrey,
|
||||
button = Color.White
|
||||
)
|
||||
|
||||
private val LightColorPalette = lightColors(
|
||||
background = Color.White,
|
||||
primary = Color.White,
|
||||
text = Color.White,
|
||||
button = DarkGrey
|
||||
)
|
||||
|
||||
object YChartsTheme {
|
||||
|
||||
val colors: YChartsColors
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalColors.current
|
||||
|
||||
val typography: YChartsTypography
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalTypography.current
|
||||
|
||||
val shapes: YChartsShapes
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalShapes.current
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun YChartsTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
typography: YChartsTypography = YChartsTheme.typography,
|
||||
shapes: YChartsShapes = YChartsTheme.shapes,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colors = if (darkTheme) DarkColorPalette else LightColorPalette
|
||||
CompositionLocalProvider(
|
||||
LocalColors provides colors,
|
||||
LocalShapes provides shapes,
|
||||
LocalTypography provides typography
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package co.yml.ycharts.app.ui.theme
|
||||
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
data class YChartsTypography(
|
||||
val header: TextStyle = TextStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 24.sp,
|
||||
letterSpacing = 0.15.sp
|
||||
),
|
||||
val button: TextStyle = TextStyle(
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
letterSpacing = 0.25.sp
|
||||
)
|
||||
)
|
||||
|
||||
internal val LocalTypography = staticCompositionLocalOf { YChartsTypography() }
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="300"
|
||||
android:fromXDelta="0%p"
|
||||
android:toXDelta="-100%p">
|
||||
</translate>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="300"
|
||||
android:fromXDelta="100%p"
|
||||
android:toXDelta="0%p">
|
||||
</translate>
|
||||
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffff"
|
||||
android:pathData="M16.62,2.99c-0.49,-0.49 -1.28,-0.49 -1.77,0L6.54,11.3c-0.39,0.39 -0.39,1.02 0,1.41l8.31,8.31c0.49,0.49 1.28,0.49 1.77,0s0.49,-1.28 0,-1.77L9.38,12l7.25,-7.25c0.48,-0.48 0.48,-1.28 -0.01,-1.76z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="dark_grey">#242222</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,41 @@
|
||||
<resources>
|
||||
<string name="app_name">YCharts</string>
|
||||
<string name="title_activity_bar_chart">BarChartActivity</string>
|
||||
<string name="title_activity_line_chart">LineChartActivity</string>
|
||||
<string name="title_activity_wave_chart">WaveChartActivity</string>
|
||||
<string name="title_activity_pie_chart">PieChartActivity</string>
|
||||
<string name="title_activity_donut_chart">DonutChartActivity</string>
|
||||
<string name="title_activity_combined_line_bar_chart">CombinedLineAndBarChartActivity</string>
|
||||
<string name="title_bar_chart">Bar Chart</string>
|
||||
<string name="title_line_chart">Line Chart</string>
|
||||
<string name="title_wave_chart">Wave Chart</string>
|
||||
<string name="title_pie_chart">Pie Chart</string>
|
||||
<string name="title_donut_chart">Donut Chart</string>
|
||||
<string name="title_bar_with_line_chart">Combined Chart</string>
|
||||
<string name="linechart_default_style">Single Line chart with default style and grid</string>
|
||||
<string name="linechart_straight_line_style">Single Linechart with Straight-Line style</string>
|
||||
<string name="linechart_dotted_style"> Dotted Single Linechart with gradient background</string>
|
||||
<string name="linechart_multiple_tones">Multicolor line-chart</string>
|
||||
<string name="combined_line_chart">Linechart with combination Multiple lines with different styles</string>
|
||||
<string name="barchart_solid_colors">Simple Barchart with solid bars</string>
|
||||
<string name="barchart_gradient_colors">Barchart with gradient bars</string>
|
||||
<string name="barchart_background_color">Barchart with background color</string>
|
||||
<string name="combined_bar_line_chart">A Combined chart with Barchart and Linechart</string>
|
||||
<string name="combined_chart_with_background">A Combined-chart with background</string>
|
||||
<string name="simple_donut_chart">A Simple Donutchart</string>
|
||||
<string name="donut_chart_with_background">A Donutchart with a background color</string>
|
||||
<string name="multiple_donuts">Multiple Donutcharts</string>
|
||||
<string name="simple_piechart">Simple Piechart</string>
|
||||
<string name="piechart_with_lables">"Piechart with slice-labels "</string>
|
||||
<string name="horizontal_bar_chart">Horizontal Barchart</string>
|
||||
<string name="grouped_bar_chart">Grouped Barchart</string>
|
||||
<string name="stacked_barchart">Stacked Barchart</string>
|
||||
<string name="simple_wave_chart">Simple Wave Chart</string>
|
||||
<string name="sine_wave_chart">Sine-Wave Chart</string>
|
||||
<string name="amplitude_wave_chart">Amplitude Wave Chart</string>
|
||||
<string name="title_activity_bubble_chart">Bubble Chart</string>
|
||||
<string name="bubble_chart">Bubblechart</string>
|
||||
<string name="gradient_bubble_chart">Gradient Bubblechart</string>
|
||||
<string name="solid_bubble_chart">Solid Bubble chart</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Theme.YCharts" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:statusBarColor">@color/dark_grey</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older that API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
@@ -0,0 +1,17 @@
|
||||
package co.yml.ycharts.app
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||