From 07d150968e17fbb2de02715c4070c09a680fc1db Mon Sep 17 00:00:00 2001 From: Avior Date: Mon, 22 Aug 2022 17:50:38 +0200 Subject: [PATCH] fix: label not correctly positionned --- .../openhealth/ui/steps/StepsHomeFragment.kt | 61 ++++++++------ .../ui/weight/ListWeightFragment.kt | 7 +- .../main/java/com/dzeio/charts/ChartView.kt | 5 +- .../com/dzeio/charts/ChartViewInterface.kt | 2 +- .../main/java/com/dzeio/charts/XAxisLabels.kt | 23 ----- .../main/java/com/dzeio/charts/axis/YAxis.kt | 42 +++++++--- .../com/dzeio/charts/axis/YAxisInterface.kt | 12 ++- .../java/com/dzeio/charts/series/BarSerie.kt | 83 +++++++++++++------ .../java/com/dzeio/charts/series/BaseSerie.kt | 2 +- .../com/dzeio/charts/utils/CanvasUtils.kt | 49 +++++++++++ 10 files changed, 191 insertions(+), 95 deletions(-) delete mode 100644 charts/src/main/java/com/dzeio/charts/XAxisLabels.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 434b4b0..c819d4f 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 @@ -47,9 +47,42 @@ class StepsHomeFragment : val chart = binding.chart - val serie = BarSerie(chart) + // setup serie + val serie = BarSerie(chart).apply { + barPaint.color = MaterialColors.getColor( + requireView(), + com.google.android.material.R.attr.colorPrimary + ) + textPaint.color = MaterialColors.getColor( + requireView(), + com.google.android.material.R.attr.colorOnPrimary + ) + } - chart.series = arrayListOf(serie) + chart.apply { + series = arrayListOf(serie) + debug = true + + yAxis.apply { + setYMin(0f) + textLabel.color = MaterialColors.getColor( + requireView(), + com.google.android.material.R.attr.colorOnPrimaryContainer + ) + linePaint.color = MaterialColors.getColor( + requireView(), + com.google.android.material.R.attr.colorOnPrimaryContainer + ) +// + onValueFormat = { value -> "${value.toInt()}" } + } + + xAxis.apply { + increment = 3600000.0 + displayCount = 168 +// displayCount = 24 + } + } viewModel.items.observe(viewLifecycleOwner) { list -> adapter.set(list) @@ -68,34 +101,12 @@ class StepsHomeFragment : // ) // chart.xAxis.labels.size = 32f - chart.yAxis.apply { - setYMin(0f) - textLabel.color = MaterialColors.getColor( - requireView(), - com.google.android.material.R.attr.colorOnBackground - ) -// linePaint.color = MaterialColors.getColor( -// requireView(), -// com.google.android.material.R.attr.colorOutline -// ) -// onValueFormat = onValueFormat@{ value, short -> -// if (short) { -// return@onValueFormat value.toInt().toString() -// } else { -// return@onValueFormat "${value.toInt()} steps" -// } -// } - } serie.entries = list.reversed().map { return@map Entry(it.timestamp.toDouble(), it.value.toFloat()) } as ArrayList - chart.xAxis.apply { - increment = (1000 * 60 * 60).toDouble() - displayCount = 24 * 7 - x = serie.entries.first().x - } + chart.xAxis.x = serie.entries.first().x // chart.xAxis.onValueFormat = onValueFormat@{ // val formatter = DateFormat.getDateTimeInstance( diff --git a/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt b/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt index fd4b5c0..2952a61 100644 --- a/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt +++ b/app/src/main/java/com/dzeio/openhealth/ui/weight/ListWeightFragment.kt @@ -2,11 +2,7 @@ package com.dzeio.openhealth.ui.weight import android.content.SharedPreferences import android.os.Bundle -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup +import android.view.* import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager @@ -37,6 +33,7 @@ class ListWeightFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + // FIXME: deprecated setHasOptionsMenu(true) if (viewModel.goalWeight != null) { diff --git a/charts/src/main/java/com/dzeio/charts/ChartView.kt b/charts/src/main/java/com/dzeio/charts/ChartView.kt index 9487f5b..2334058 100644 --- a/charts/src/main/java/com/dzeio/charts/ChartView.kt +++ b/charts/src/main/java/com/dzeio/charts/ChartView.kt @@ -50,9 +50,12 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet }, debugStrokePaint) } + // right distance from the yAxis + val rightDistance = yAxis.onDraw(canvas) + // chart draw rectangle rect.apply { - set(0f, 0f, width.toFloat(), height.toFloat()) + set(0f, 8f, width.toFloat() - 16f - rightDistance, height.toFloat() - 16f) } for (serie in series) { diff --git a/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt b/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt index 24b0237..9abc222 100644 --- a/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt +++ b/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt @@ -29,7 +29,7 @@ interface ChartViewInterface { var series: ArrayList /** - * refresh EVERYTHING + * refresh the chart */ fun refresh() } \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/XAxisLabels.kt b/charts/src/main/java/com/dzeio/charts/XAxisLabels.kt deleted file mode 100644 index 564011d..0000000 --- a/charts/src/main/java/com/dzeio/charts/XAxisLabels.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.dzeio.charts - -import android.graphics.Color -import android.graphics.Paint -import androidx.annotation.ColorInt - -class XAxisLabels { - - var size = 25f - - @ColorInt - var color: Int = Color.parseColor("#9B9A9B") - - fun build(): Paint { - return Paint().also { - it.isAntiAlias = true - it.color = color - it.textSize = size - it.isFakeBoldText = true - it.textAlign = Paint.Align.CENTER - } - } -} diff --git a/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt b/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt index 9ec6a17..f3a5f66 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt @@ -3,27 +3,37 @@ package com.dzeio.charts.axis import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint -import android.graphics.RectF +import android.graphics.Rect import com.dzeio.charts.ChartViewInterface +import com.dzeio.charts.utils.drawDottedLine class YAxis( private val view: ChartViewInterface ) : YAxisInterface { - override var enabled = false + override var enabled = true override val textLabel = Paint().apply { isAntiAlias = true color = Color.parseColor("#FC496D") textSize = 30f - textAlign = Paint.Align.RIGHT + textAlign = Paint.Align.LEFT } + override val linePaint = Paint().apply { + isAntiAlias = true + color = Color.BLUE + } + + var onValueFormat: (value: Float) -> String = { it -> it.toString()} + override var labelCount: Int = 3 private var min: Float? = null private var max: Float? = null + private val rect = Rect() + override fun setYMin(yMin: Float?): YAxisInterface { min = yMin return this @@ -66,22 +76,34 @@ class YAxis( } } - override fun onDraw(canvas: Canvas, drawLocation: RectF) { + override fun onDraw(canvas: Canvas): Float { + if (!enabled) { + return 0f + } val min = getYMin() val max = getYMax() - min - val top = drawLocation.top - val bottom = drawLocation.bottom + val top = 0 + val bottom = canvas.height.toFloat() + var maxWidth = 0f val increment = (bottom - top) / labelCount val valueIncrement = (max - min) / labelCount for (index in 0 until labelCount) { + val text = onValueFormat((valueIncrement * (index + 1))).toString() + textLabel.getTextBounds(text, 0, text.length, rect) + maxWidth = maxWidth.coerceAtLeast(rect.width().toFloat()) + + val posY = bottom - (index + 1) * increment + canvas.drawText( - (valueIncrement * (labelCount + 1)).toString(), - bottom - (index + 1) * increment, - drawLocation.right, + text, + canvas.width - rect.width().toFloat(), + posY + rect.height() + 8f, textLabel ) + canvas.drawDottedLine(0f, posY, canvas.width.toFloat(), posY, 40f, linePaint) + } - TODO("IDK if it works tbh") + return maxWidth } } \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/axis/YAxisInterface.kt b/charts/src/main/java/com/dzeio/charts/axis/YAxisInterface.kt index 732ad82..0617f5b 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/YAxisInterface.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/YAxisInterface.kt @@ -2,7 +2,6 @@ package com.dzeio.charts.axis import android.graphics.Canvas import android.graphics.Paint -import android.graphics.RectF sealed interface YAxisInterface { @@ -52,7 +51,14 @@ sealed interface YAxisInterface { val textLabel: Paint /** - * function that draw our legend + * paint for the dotted line */ - fun onDraw(canvas: Canvas, drawLocation: RectF) + val linePaint: Paint + + /** + * function that draw our legend + * + * @return the width of the sidebar + */ + fun onDraw(canvas: Canvas): Float } \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt b/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt index 1fff622..0cf67fe 100644 --- a/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt +++ b/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt @@ -1,10 +1,9 @@ package com.dzeio.charts.series -import android.graphics.Canvas -import android.graphics.Color -import android.graphics.Paint -import android.graphics.RectF +import android.graphics.* +import android.util.Log import com.dzeio.charts.ChartView +import com.dzeio.charts.utils.drawRoundRect class BarSerie( private val view: ChartView @@ -19,6 +18,15 @@ class BarSerie( color = Color.parseColor("#123456") } + val textPaint = Paint().apply { + isAntiAlias = true + color = Color.parseColor("#FC496D") + textSize = 30f + textAlign = Paint.Align.CENTER + } + + private val rect = Rect() + override fun onDraw(canvas: Canvas, drawableSpace: RectF) { val spacing = drawableSpace.width() / view.xAxis.displayCount / 10 val barWidth = drawableSpace.width() / view.xAxis.displayCount - spacing @@ -30,38 +38,61 @@ class BarSerie( for (entry in displayedEntries) { // calculated height in percent from 0 to 100 - val height = (1 - entry.y / max) * drawableSpace.height() - // -1.945763981752553E-21 - // 2.103653925902835E-21 - val posX = view.xAxis.getPositionOnRect(entry, drawableSpace) - view.xAxis.getXOffset(drawableSpace) - canvas.width + val top = (1 - entry.y / max) * drawableSpace.height() + val posX = (view.xAxis.getPositionOnRect(entry, drawableSpace) - view.xAxis.getXOffset(drawableSpace)).toFloat() // Log.d(TAG, "gpor = ${view.xAxis.getPositionOnRect(entry, space)}, gxo = ${view.xAxis.getXOffset(space)}") // Log.d(TAG, "max = $max, y = ${entry.y}, height = $height") // Log.d(TAG, "posX: ${posX / 60 / 60 / 1000}, offsetX = ${view.xAxis.x / (1000 * 60 * 60)}, x = ${entry.x / (1000 * 60 * 60)}, pouet: ${(view.xAxis.x + view.xAxis.displayCount * view.xAxis.increment) / (1000 * 60 * 60)}") -// Log.d( -// TAG, """ -// ${posX.toFloat()}, -// $height, -// ${(posX + barWidth).toFloat()}, -// ${space.bottom}""".trimIndent() -// ) + Log.d( + TAG, """ + ${posX}, + $top, + ${(posX + barWidth).toFloat()}, + ${drawableSpace.bottom}""".trimIndent() + ) - canvas.drawRect( - posX.toFloat(), - height, - (posX + barWidth).toFloat(), + val right = (posX + barWidth).toFloat().coerceAtMost(drawableSpace.right) + + if (posX > right) { + continue + } + + canvas.drawRoundRect( + posX, + top, + right, drawableSpace.bottom, +// 8f, 8f, + 32f, + 32f, + 0f, + 0f, barPaint ) - canvas.drawText( - entry.y.toString(), - (posX + barWidth / 2).toFloat(), - drawableSpace.bottom / 2, - view.yAxis.textLabel.apply { - textAlign = Paint.Align.CENTER + // handle text display + val text = view.yAxis.onValueFormat(entry.y) - } + textPaint.getTextBounds(text, 0, text.length, rect) + + val textLeft = (posX + barWidth / 2).toFloat() + + if (textLeft + rect.width() / 2 > right) { + continue + } + + val doDisplayIn = + rect.height() + 40f < drawableSpace.bottom - top && + rect.width() < barWidth + + + + canvas.drawText( + text, + textLeft, + if (doDisplayIn) top + rect.height() + 20f else top - 20f, + textPaint ) } } diff --git a/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt b/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt index 5ad3186..9f354da 100644 --- a/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt +++ b/charts/src/main/java/com/dzeio/charts/series/BaseSerie.kt @@ -22,7 +22,7 @@ sealed class BaseSerie( // -+ view.xAxis.increment = one out of display val minX = view.xAxis.x - view.xAxis.increment val maxX = - view.xAxis.x + view.xAxis.displayCount * 2 * view.xAxis.increment + view.xAxis.increment + view.xAxis.x + view.xAxis.displayCount * view.xAxis.increment + view.xAxis.increment return entries.filter { return@filter it.x in minX..maxX diff --git a/charts/src/main/java/com/dzeio/charts/utils/CanvasUtils.kt b/charts/src/main/java/com/dzeio/charts/utils/CanvasUtils.kt index 242e8df..337d8d3 100644 --- a/charts/src/main/java/com/dzeio/charts/utils/CanvasUtils.kt +++ b/charts/src/main/java/com/dzeio/charts/utils/CanvasUtils.kt @@ -2,6 +2,7 @@ package com.dzeio.charts.utils import android.graphics.Canvas import android.graphics.Paint +import android.graphics.RectF import kotlin.math.sqrt fun Canvas.drawDottedLine( @@ -46,4 +47,52 @@ fun Canvas.drawDottedLine( // total line startX, endX, startY, endY // total line length } +} + +/** + * A more customizable drawRoundRect function + */ +fun Canvas.drawRoundRect(left: Float, top: Float, right: Float, bottom: Float, topLeft: Float, topRight: Float, bottomLeft: Float, bottomRight: Float, paint: Paint) { + val maxRound = arrayOf(topLeft, topRight, bottomLeft, bottomRight).maxOf { it } + val width = right - left + val height = bottom - top + + // draw first/global rect + drawRoundRect(left, top, right, bottom, maxRound, maxRound, paint) + + // top left border + if (topLeft == 0f) { + drawRect(left, top, left + width / 2, top + height / 2, paint) + } else { + drawRoundRect(left, top, left + width / 2, top + height / 2, topLeft, topLeft, paint) + } + + // top right border + if (topRight == 0f) { + drawRect(right - width / 2, top, right, top + height / 2, paint) + } else { + drawRoundRect(right - width / 2, top, right, top + height / 2, topRight, topRight, paint) + } + + // bottom left border + if (bottomLeft == 0f) { + drawRect(left, bottom - height / 2, left + width / 2, bottom, paint) + } else { + drawRoundRect(left, bottom - height / 2, left + width / 2, bottom, bottomLeft, bottomLeft, paint) + } + + // bottom right border + if (bottomRight == 0f) { + drawRect(right - width / 2, bottom - height / 2, right, bottom, paint) + } else { + drawRoundRect(right - width / 2, bottom - height / 2, right, bottom, bottomRight, bottomRight, paint) + } + +} + +/** + * A more customizable drawRoundRect function + */ +fun Canvas.drawRoundRect(rect: RectF, topLeft: Float, topRight: Float, bottomLeft: Float, bottomRight: Float, paint: Paint) { + drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, topLeft, topRight, bottomLeft, bottomRight, paint) } \ No newline at end of file