From 196fcf5da0b8ed5610b28e9d205e1b195651b9ee Mon Sep 17 00:00:00 2001 From: Avior Date: Mon, 25 Jul 2022 17:37:02 +0200 Subject: [PATCH] misc: Continue working on Chart --- .../openhealth/ui/steps/StepsHomeFragment.kt | 6 ++ charts/src/main/java/com/dzeio/charts/Axis.kt | 6 ++ .../src/main/java/com/dzeio/charts/Entry.kt | 6 ++ .../com/dzeio/charts/views/BarChartView.kt | 79 ++++++++++++++----- 4 files changed, 78 insertions(+), 19 deletions(-) create mode 100644 charts/src/main/java/com/dzeio/charts/Axis.kt create mode 100644 charts/src/main/java/com/dzeio/charts/Entry.kt diff --git a/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt index 4e9def1..16a86d6 100644 --- a/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt +++ b/app/src/main/java/com/dzeio/openhealth/ui/steps/StepsHomeFragment.kt @@ -41,6 +41,8 @@ class StepsHomeFragment : viewModel.items.observe(viewLifecycleOwner) { list -> adapter.set(list) + chart.numberOfEntries = list.size + chart.numberOfLabels = 2 val strings = ArrayList() val values = ArrayList() @@ -50,10 +52,14 @@ class StepsHomeFragment : values.add(it.value) } + chart.yAxis.max = 10 + + chart.setBottomTextList(strings) chart.setDataList( values ) + chart.refresh() } } } diff --git a/charts/src/main/java/com/dzeio/charts/Axis.kt b/charts/src/main/java/com/dzeio/charts/Axis.kt new file mode 100644 index 0000000..acbab91 --- /dev/null +++ b/charts/src/main/java/com/dzeio/charts/Axis.kt @@ -0,0 +1,6 @@ +package com.dzeio.charts + +class Axis { + var max: T? = null + var min: T? = null +} \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/Entry.kt b/charts/src/main/java/com/dzeio/charts/Entry.kt new file mode 100644 index 0000000..4eeec35 --- /dev/null +++ b/charts/src/main/java/com/dzeio/charts/Entry.kt @@ -0,0 +1,6 @@ +package com.dzeio.charts + +data class Entry( + val x: Float, + val y: Double +) \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/views/BarChartView.kt b/charts/src/main/java/com/dzeio/charts/views/BarChartView.kt index 201a03f..2556fca 100644 --- a/charts/src/main/java/com/dzeio/charts/views/BarChartView.kt +++ b/charts/src/main/java/com/dzeio/charts/views/BarChartView.kt @@ -8,7 +8,11 @@ import android.graphics.Rect import android.util.AttributeSet import android.util.Log import android.view.View +import com.dzeio.charts.Axis +import com.dzeio.charts.Entry import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min class BarChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) : View(context, attrs) { @@ -20,23 +24,21 @@ class BarChartView @JvmOverloads constructor(context: Context?, attrs: Attribute /** * Nunber of entries displayed at the same time */ - val numberOfEntries = 5 + var numberOfEntries = 5 /** * Number of labels displayed at the same time */ - val numberOfLabels = 3 + var numberOfLabels = 3 /** * Spacing between entries */ - val spacing = 22 + var spacing = 22 - /** - * top margin from the canvas - */ - @Deprecated("Not needed anymore, Use the parent Padding/Margin") - private val topMargin: Int = 5 + val xAxis: Axis = Axis() + + val yAxis: Axis = Axis() private val textTopMargin = 5 @@ -84,13 +86,25 @@ class BarChartView @JvmOverloads constructor(context: Context?, attrs: Attribute } } + fun setList(list: ArrayList) { + + } + + fun refresh(animate: Boolean = true) { + if (animate) { + removeCallbacks(animator) + post(animator) + } else { + postInvalidate() + } + } + /** * dataList will be reset when called is method. * * @param bottomStringList The String ArrayList in the bottom. */ fun setBottomTextList(bottomStringList: ArrayList?) { - barWidth = measuredWidth / numberOfEntries - spacing bottomTextList = bottomStringList val r = Rect() bottomTextDescent = 0 @@ -99,7 +113,7 @@ class BarChartView @JvmOverloads constructor(context: Context?, attrs: Attribute if (bottomTextHeight < r.height()) { bottomTextHeight = r.height() } - Log.d(TAG, measuredWidth.toString()) +// Log.d(TAG, measuredWidth.toString()) // if (autoSetWidth && barWidth < r.width()) { // barWidth = r.width() // } @@ -107,7 +121,6 @@ class BarChartView @JvmOverloads constructor(context: Context?, attrs: Attribute bottomTextDescent = abs(r.bottom) } } - postInvalidate() } /** @@ -116,7 +129,7 @@ class BarChartView @JvmOverloads constructor(context: Context?, attrs: Attribute fun setDataList(list: ArrayList) { barWidth = measuredWidth / numberOfEntries - spacing // Calculate max - val max = list.reduce { acc, i -> if (acc > i) return@reduce acc else return@reduce i } + val max = yAxis.max ?: list.reduce { acc, i -> return@reduce if (acc > i) acc else i } targetPercentList = ArrayList() for (integer in list) { @@ -135,35 +148,63 @@ class BarChartView @JvmOverloads constructor(context: Context?, attrs: Attribute percentList.removeAt(percentList.size - 1) } } - - removeCallbacks(animator) - post(animator) } override fun onDraw(canvas: Canvas) { if (percentList.isNotEmpty()) { for (i in 1 until percentList.size) { val left = spacing * i + barWidth * (i - 1) - Log.d(TAG, "$spacing, $i, $barWidth = $left") +// Log.d(TAG, "$spacing, $i, $barWidth = $left") val right = (spacing + barWidth) * i val bottom = height - bottomTextHeight - textTopMargin - val top = topMargin + ((bottom - topMargin) * percentList[i - 1]) + val top = bottom * percentList[i - 1] rect.set(left, top.toInt(), right, bottom) canvas.drawRect(rect, fgPaint) } } - if (bottomTextList != null && !bottomTextList!!.isEmpty()) { + if (bottomTextList != null && bottomTextList!!.isNotEmpty() && numberOfLabels > 0) { + val rect = Rect() + val size = bottomTextList!!.size var i = 1 + var items = size / max(2, (numberOfLabels - 2)) + + // handle cases where size is even and numberOfLabels is 3 + if (size % 2 != 0) { + items += 1 + } + + Log.i(TAG, "$size / max($numberOfLabels - 2, 2) = $items") for (s in bottomTextList!!) { + + if ((numberOfLabels <= 2 || i % items != 0) && i != 1 && i != size) { + i++ + continue + } + + Log.i(TAG, "Drawing $i") + + textPaint.getTextBounds(s, 0, s.length, rect) + canvas.drawText( s, - (spacing * i + barWidth * (i - 1) + barWidth / 2).toFloat(), + // handle last entry overflowing + min( + // handle first entry overflowing + max( + (spacing * i + barWidth * (i - 1) + barWidth / 2).toFloat(), + rect.width() / 2f + ), + measuredWidth - rect.width() / 2f + ), (height - bottomTextDescent).toFloat(), textPaint ) i++ + if (numberOfLabels == 1) { + break + } } } }