From 5b1f8d4d6126c7cb18aa81ba485069ba3a24764b Mon Sep 17 00:00:00 2001 From: Hannes Achleitner Date: Tue, 30 Dec 2025 12:51:35 +0100 Subject: [PATCH] Add timeline activity --- app/src/main/AndroidManifest.xml | 1 + .../info/appdev/chartexample/DataTools.kt | 15 ++ .../appdev/chartexample/TimeLineActivity.kt | 151 ++++++++++++++++++ .../formatter/UnixTimeAxisValueFormatter.kt | 16 ++ .../chartexample/notimportant/MainActivity.kt | 2 + ...TimeLineActivity-Timeline-1SampleClick.png | Bin 0 -> 21619 bytes 6 files changed, 185 insertions(+) create mode 100644 app/src/main/kotlin/info/appdev/chartexample/TimeLineActivity.kt create mode 100644 app/src/main/kotlin/info/appdev/chartexample/formatter/UnixTimeAxisValueFormatter.kt create mode 100644 screenshotsToCompare9/StartTest_smokeTestStart-43-TimeLineActivity-Timeline-1SampleClick.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 21f507e72..7850e0641 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,6 +56,7 @@ + diff --git a/app/src/main/kotlin/info/appdev/chartexample/DataTools.kt b/app/src/main/kotlin/info/appdev/chartexample/DataTools.kt index 386f658e4..abf30e942 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/DataTools.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/DataTools.kt @@ -13,6 +13,8 @@ import info.appdev.charting.interfaces.dataprovider.LineDataProvider import info.appdev.charting.interfaces.datasets.ILineDataSet import info.appdev.charting.utils.getSDKInt import timber.log.Timber +import kotlin.math.PI +import kotlin.math.sin class DataTools { companion object { @@ -135,6 +137,19 @@ class DataTools { fun getValues(size: Int) = VAL_102.copyOf(size) + /** + * Generates points for n complete sine waves. + * @param cycles Number of complete sine graphs (n) + * @param pointsPerCycle Number of data points to generate for each cycle + */ + fun generateSineWaves(cycles: Int, pointsPerCycle: Int): List { + val totalPoints = cycles * pointsPerCycle + val stepSize = (2 * PI * cycles) / totalPoints + + return (0 until totalPoints).map { i -> + sin(i * stepSize) + } + } fun getMuchValues(size: Int): Array { var result = VAL_102.copyOf(VAL_102.size) while (result.size < size) diff --git a/app/src/main/kotlin/info/appdev/chartexample/TimeLineActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/TimeLineActivity.kt new file mode 100644 index 000000000..4b7325eef --- /dev/null +++ b/app/src/main/kotlin/info/appdev/chartexample/TimeLineActivity.kt @@ -0,0 +1,151 @@ +package info.appdev.chartexample + +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import androidx.core.net.toUri +import info.appdev.chartexample.DataTools.Companion.generateSineWaves +import info.appdev.chartexample.databinding.ActivityLinechartNoseekbarBinding +import info.appdev.chartexample.formatter.UnixTimeAxisValueFormatter +import info.appdev.chartexample.notimportant.DemoBase +import info.appdev.charting.components.Description +import info.appdev.charting.components.Legend.LegendForm +import info.appdev.charting.components.XAxis.XAxisPosition +import info.appdev.charting.components.YAxis +import info.appdev.charting.data.Entry +import info.appdev.charting.data.LineData +import info.appdev.charting.data.LineDataSet +import info.appdev.charting.formatter.IFillFormatter +import info.appdev.charting.interfaces.dataprovider.LineDataProvider +import info.appdev.charting.interfaces.datasets.ILineDataSet + +class TimeLineActivity : DemoBase() { + private lateinit var binding: ActivityLinechartNoseekbarBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityLinechartNoseekbarBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.chart1.setBackgroundColor(Color.WHITE) + binding.chart1.setDrawGridBackground(true) + + binding.chart1.setDrawBorders(true) + + // no description text + binding.chart1.description = Description().apply { + text = "Sinus Time Line" + } + binding.chart1.description.isEnabled = true + + binding.chart1.xAxis.apply { +// enableGridDashedLine(10f, 10f, 0f) +// this.position = XAxis.XAxisPosition.BOTH_SIDED + isEnabled = true + position = XAxisPosition.BOTTOM + typeface = tfLight + labelRotationAngle = 45f + setDrawGridLines(false) +// granularity = 1f // only intervals of 1 day + labelCount = 7 + valueFormatter = UnixTimeAxisValueFormatter("yyyy-MM-dd HH:mm:ss") + } + + // if disabled, scaling can be done on x- and y-axis separately + binding.chart1.setPinchZoom(false) + + binding.chart1.legend.apply { + isEnabled = false + form = LegendForm.LINE + } + + binding.chart1.axisLeft.apply { + axisMaximum = 150f + axisMinimum = -50f + setDrawAxisLine(true) + setDrawZeroLine(true) + setDrawGridLines(true) + } + + binding.chart1.axisRight.isEnabled = false + + setData(60f, TIME_OFFSET) + + binding.chart1.invalidate() + } + + @Suppress("SameParameterValue") + private fun setData(range: Float, timeOffset: Long) { + + val sampleEntries = generateSineWaves(3, 30) + .mapIndexed { index, data -> + val valueY = (data.toFloat() * range) + 50 + Entry(timeOffset + index.toFloat() * 1000, valueY) + }.toMutableList() + + val set1: LineDataSet + + if (binding.chart1.lineData.dataSetCount > 0) { + set1 = binding.chart1.lineData.getDataSetByIndex(0) as LineDataSet + set1.entries = sampleEntries + binding.chart1.lineData.notifyDataChanged() + binding.chart1.notifyDataSetChanged() + } else { + // create a dataset and give it a type + set1 = LineDataSet(sampleEntries, "DataSet 1") + + set1.axisDependency = YAxis.AxisDependency.LEFT + set1.color = Color.rgb(255, 241, 46) + set1.isDrawCirclesEnabled = false + set1.lineWidth = 2f + set1.circleRadius = 3f + set1.fillAlpha = 255 + set1.isDrawFilledEnabled = true + set1.fillColor = Color.WHITE + set1.highLightColor = Color.rgb(244, 117, 117) + set1.isDrawCircleHoleEnabled = false + set1.fillFormatter = object : IFillFormatter { + override fun getFillLinePosition(dataSet: ILineDataSet?, dataProvider: LineDataProvider): Float { + // change the return value here to better understand the effect + // return 0; + return binding.chart1.axisLeft.axisMinimum + } + } + + val dataSets = ArrayList() + dataSets.add(set1) // add the data sets + + // create a data object with the data sets + val data = LineData(dataSets) + data.setDrawValues(false) + + binding.chart1.setData(data) + } + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.only_github, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.viewGithub -> { + val i = Intent(Intent.ACTION_VIEW) + i.data = + "https://github.com/AppDevNext/AndroidChart/blob/master/app/src/main/java/info/appdev/chartexample/FilledLineActivity.kt".toUri() + startActivity(i) + } + } + + return true + } + + public override fun saveToGallery() = Unit // Intentionally left empty + + companion object { + const val TIME_OFFSET = 1767105583L + } +} diff --git a/app/src/main/kotlin/info/appdev/chartexample/formatter/UnixTimeAxisValueFormatter.kt b/app/src/main/kotlin/info/appdev/chartexample/formatter/UnixTimeAxisValueFormatter.kt new file mode 100644 index 000000000..3efeb6ae3 --- /dev/null +++ b/app/src/main/kotlin/info/appdev/chartexample/formatter/UnixTimeAxisValueFormatter.kt @@ -0,0 +1,16 @@ +package info.appdev.chartexample.formatter + +import info.appdev.charting.components.AxisBase +import info.appdev.charting.formatter.IAxisValueFormatter +import java.text.SimpleDateFormat +import java.util.Locale + +class UnixTimeAxisValueFormatter(val format: String = "yyyy-MM-dd'T'HH:mm:ss'Z'") : IAxisValueFormatter { + + val sdf = SimpleDateFormat(format, Locale.getDefault()) + + override fun getFormattedValue(value: Float, axis: AxisBase?): String { + return sdf.format(value * 1000L) + } + +} diff --git a/app/src/main/kotlin/info/appdev/chartexample/notimportant/MainActivity.kt b/app/src/main/kotlin/info/appdev/chartexample/notimportant/MainActivity.kt index fe41d4030..c8f06c2e3 100644 --- a/app/src/main/kotlin/info/appdev/chartexample/notimportant/MainActivity.kt +++ b/app/src/main/kotlin/info/appdev/chartexample/notimportant/MainActivity.kt @@ -77,6 +77,7 @@ import info.appdev.chartexample.ScrollViewActivity import info.appdev.chartexample.SpecificPositionsLineChartActivity import info.appdev.chartexample.StackedBarActivity import info.appdev.chartexample.StackedBarActivityNegative +import info.appdev.chartexample.TimeLineActivity import info.appdev.chartexample.compose.HorizontalBarComposeActivity import info.appdev.chartexample.fragments.ViewPagerSimpleChartDemo @@ -212,6 +213,7 @@ class MainActivity : ComponentActivity() { add(ContentItem("Demonstrate and fix issues")) add(ContentItem("Gradient", "Show a gradient edge case", GradientActivity::class.java)) + add(ContentItem("Timeline", "Show a time line with Unix timestamp", TimeLineActivity::class.java)) } } } diff --git a/screenshotsToCompare9/StartTest_smokeTestStart-43-TimeLineActivity-Timeline-1SampleClick.png b/screenshotsToCompare9/StartTest_smokeTestStart-43-TimeLineActivity-Timeline-1SampleClick.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8c55ad3d34e683820d83d88721a56060421160 GIT binary patch literal 21619 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