Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import org.junit.Test
import org.junit.rules.TestName
import org.junit.runner.RunWith
import timber.log.Timber
import kotlin.jvm.java


@RunWith(AndroidJUnit4::class)
Expand Down Expand Up @@ -278,6 +279,7 @@ class StartTest {
contentItem.clazz == HorizontalBarFullComposeActivity::class.java ||
contentItem.clazz == MultiLineComposeActivity::class.java ||
contentItem.clazz == GradientActivity::class.java ||
contentItem.clazz == TimeBarActivity::class.java ||
contentItem.clazz == TimeLineActivity::class.java
) {
// These charts have less clickable area, so skip further clicks
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<activity android:name="info.appdev.chartexample.HalfPieChartActivity" />
<activity android:name="info.appdev.chartexample.SpecificPositionsLineChartActivity" />
<activity android:name="info.appdev.chartexample.TimeLineActivity" />
<activity android:name="info.appdev.chartexample.TimeBarActivity" />
</application>

</manifest>
251 changes: 251 additions & 0 deletions app/src/main/kotlin/info/appdev/chartexample/TimeBarActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
package info.appdev.chartexample

import android.Manifest
import android.R.attr.entries
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.net.toUri
import info.appdev.chartexample.DataTools.Companion.getValues
import info.appdev.chartexample.TimeLineActivity.Companion.TIME_OFFSET
import info.appdev.chartexample.databinding.ActivityHorizontalbarchartBinding
import info.appdev.chartexample.formatter.TimeRangeValueFormatter
import info.appdev.chartexample.formatter.UnixTimeAxisValueFormatter
import info.appdev.chartexample.formatter.UnixTimeRelative2NowAxisValueFormatter
import info.appdev.chartexample.formatter.UnixTimeValueFormatter
import info.appdev.chartexample.notimportant.DemoBase
import info.appdev.charting.components.Description
import info.appdev.charting.components.Legend
import info.appdev.charting.components.XAxis.XAxisPosition
import info.appdev.charting.data.BarData
import info.appdev.charting.data.BarDataSet
import info.appdev.charting.data.BarEntryDouble
import info.appdev.charting.data.BarEntryFloat
import info.appdev.charting.interfaces.datasets.IBarDataSet
import timber.log.Timber

class TimeBarActivity : DemoBase(), OnSeekBarChangeListener {

private lateinit var binding: ActivityHorizontalbarchartBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHorizontalbarchartBinding.inflate(layoutInflater)
setContentView(binding.root)

binding.seekBarX.setOnSeekBarChangeListener(this)
binding.seekBarY.setOnSeekBarChangeListener(this)

binding.chart1.isLogging = true
binding.chart1.isDrawBarShadow = false
binding.chart1.isDrawValueAboveBar = true
binding.chart1.description.isEnabled = true
binding.chart1.description = Description().apply {
text = "Time Bar Line"
}

// if more than 60 entries are displayed in the chart, no values will be drawn
binding.chart1.setMaxVisibleValueCount(60)

// scaling can now only be done on x- and y-axis separately
binding.chart1.isPinchZoom = false

// draw shadows for each bar that show the maximum value
// chart.setDrawBarShadow(true);
binding.chart1.setDrawGridBackground(false)

binding.chart1.xAxis.apply {
position = XAxisPosition.BOTTOM
typeface = tfLight
isDrawAxisLine = true
isDrawGridLines = true
granularity = 10f
// valueFormatter = UnixTimeAxisValueFormatter("HH:mm:ss")
}

// binding.chart1.axisLeft.apply {
// typeface = tfLight
// isDrawAxisLine = true
// isDrawGridLines = true
// axisMinimum = 0f // this replaces setStartAtZero(true)
// }

binding.chart1.axisRight.apply {
typeface = tfLight
isDrawAxisLine = true
isDrawGridLines = false
axisMinimum = 0f // this replaces setStartAtZero(true)
valueFormatter = UnixTimeRelative2NowAxisValueFormatter("HH:mm:ss")
}

binding.chart1.setFitBars(true)
binding.chart1.animateY(2500)

// setting data
binding.seekBarX.progress = 4
binding.seekBarY.progress = 12

binding.chart1.legend.apply {
verticalAlignment = Legend.LegendVerticalAlignment.BOTTOM
horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT
orientation = Legend.LegendOrientation.HORIZONTAL
setDrawInside(false)
formSize = 8f
xEntrySpace = 4f
}
}

private fun setData(count: Int) {
val barWidth = 9f
val spaceForBar = 10.0
val values = ArrayList<BarEntryDouble>()
val sampleValues = getValues(100).map { (it!! * 100).toInt() }

var previousTimeOffset: Double = 0.0 //TIME_OFFSET.toDouble()
for (i in 0..<count) {
Timber.d("add ${sampleValues[i]}s to $previousTimeOffset")
val yValue = sampleValues[i] + previousTimeOffset
val value = BarEntryDouble(
x = i * spaceForBar,
vals = doubleArrayOf(previousTimeOffset, yValue),
icon = ResourcesCompat.getDrawable(resources, R.drawable.star, null)
)
values.add(value)
previousTimeOffset = yValue
}

Timber.d(values.joinToString(separator = "\n"))

val set1: BarDataSet

if (binding.chart1.barData != null &&
binding.chart1.barData!!.dataSetCount > 0
) {
set1 = binding.chart1.barData!!.getDataSetByIndex(0) as BarDataSet
@Suppress("UNCHECKED_CAST")
set1.entries = values as MutableList<BarEntryFloat>
binding.chart1.barData?.notifyDataChanged()
binding.chart1.notifyDataSetChanged()
} else {
@Suppress("UNCHECKED_CAST")
set1 = BarDataSet(values as MutableList<BarEntryFloat>, "Bar DataSet")
set1.setColors(
Color.GREEN,
Color.BLUE,
Color.YELLOW
)

set1.isDrawIcons = false

val dataSets = ArrayList<IBarDataSet>()
dataSets.add(set1)

val data = BarData(dataSets)
data.setValueTextSize(10f)
data.setValueTypeface(tfLight)
data.setValueFormatter(TimeRangeValueFormatter("HH:mm:ss"))
data.barWidth = barWidth
binding.chart1.data = data
}
}

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.bar, 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/HorizontalBarChartActivity.kt".toUri()
startActivity(i)
}

R.id.actionToggleValues -> {
binding.chart1.barData?.dataSets?.forEach {
it.isDrawValues = !it.isDrawValues
}
binding.chart1.invalidate()
}

R.id.actionToggleIcons -> {
binding.chart1.barData?.dataSets?.forEach { set ->
set.isDrawIcons = !set.isDrawIcons
}
binding.chart1.invalidate()
}

R.id.actionToggleHighlight -> {
binding.chart1.barData?.let { data ->
data.isHighlight = !data.isHighlight
binding.chart1.invalidate()
}
}

R.id.actionTogglePinch -> {
binding.chart1.isPinchZoom = !binding.chart1.isPinchZoom
binding.chart1.invalidate()
}

R.id.actionToggleAutoScaleMinMax -> {
binding.chart1.isAutoScaleMinMax = !binding.chart1.isAutoScaleMinMax
binding.chart1.notifyDataSetChanged()
}

R.id.actionToggleBarBorders -> {
binding.chart1.barData?.dataSets?.map { it as BarDataSet }?.forEach { set ->
set.barBorderWidth = if (set.barBorderWidth == 1f) 0f else 1f
}
binding.chart1.invalidate()
}

R.id.animateX -> {
binding.chart1.animateX(2000)
}

R.id.animateY -> {
binding.chart1.animateY(2000)
}

R.id.animateXY -> {
binding.chart1.animateXY(2000, 2000)
}

R.id.actionSave -> {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
saveToGallery()
} else {
requestStoragePermission(binding.chart1)
}
}
}
return true
}

override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
binding.tvXMax.text = binding.seekBarX.progress.toString()
binding.tvYMax.text = binding.seekBarY.progress.toString()

setData(binding.seekBarX.progress)
binding.chart1.setFitBars(true)
binding.chart1.invalidate()
}

override fun saveToGallery() {
saveToGallery(binding.chart1, "HorizontalBarChartActivity")
}

override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit

override fun onStopTrackingTouch(seekBar: SeekBar?) = Unit

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,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.TimeBarActivity
import info.appdev.chartexample.TimeLineActivity
import info.appdev.chartexample.compose.HorizontalBarComposeActivity
import info.appdev.chartexample.compose.HorizontalBarFullComposeActivity
Expand Down Expand Up @@ -219,6 +220,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))
add(ContentItem("TimeBar", "Show a time line with Unix timestamp", TimeBarActivity::class.java))
}
}
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading