1
0
mirror of https://github.com/dzeiocom/OpenHealth.git synced 2025-04-23 19:32:11 +00:00

fix: label not correctly positionned

This commit is contained in:
Florian Bouillon 2022-08-22 17:50:38 +02:00
parent 57eef94f31
commit 07d150968e
10 changed files with 191 additions and 95 deletions

View File

@ -47,9 +47,42 @@ class StepsHomeFragment :
val chart = binding.chart 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 -> viewModel.items.observe(viewLifecycleOwner) { list ->
adapter.set(list) adapter.set(list)
@ -68,34 +101,12 @@ class StepsHomeFragment :
// ) // )
// chart.xAxis.labels.size = 32f // 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 { serie.entries = list.reversed().map {
return@map Entry(it.timestamp.toDouble(), it.value.toFloat()) return@map Entry(it.timestamp.toDouble(), it.value.toFloat())
} as ArrayList<Entry> } as ArrayList<Entry>
chart.xAxis.apply { chart.xAxis.x = serie.entries.first().x
increment = (1000 * 60 * 60).toDouble()
displayCount = 24 * 7
x = serie.entries.first().x
}
// chart.xAxis.onValueFormat = onValueFormat@{ // chart.xAxis.onValueFormat = onValueFormat@{
// val formatter = DateFormat.getDateTimeInstance( // val formatter = DateFormat.getDateTimeInstance(

View File

@ -2,11 +2,7 @@ package com.dzeio.openhealth.ui.weight
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.*
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@ -37,6 +33,7 @@ class ListWeightFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// FIXME: deprecated
setHasOptionsMenu(true) setHasOptionsMenu(true)
if (viewModel.goalWeight != null) { if (viewModel.goalWeight != null) {

View File

@ -50,9 +50,12 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet
}, debugStrokePaint) }, debugStrokePaint)
} }
// right distance from the yAxis
val rightDistance = yAxis.onDraw(canvas)
// chart draw rectangle // chart draw rectangle
rect.apply { rect.apply {
set(0f, 0f, width.toFloat(), height.toFloat()) set(0f, 8f, width.toFloat() - 16f - rightDistance, height.toFloat() - 16f)
} }
for (serie in series) { for (serie in series) {

View File

@ -29,7 +29,7 @@ interface ChartViewInterface {
var series: ArrayList<SerieInterface> var series: ArrayList<SerieInterface>
/** /**
* refresh EVERYTHING * refresh the chart
*/ */
fun refresh() fun refresh()
} }

View File

@ -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
}
}
}

View File

@ -3,27 +3,37 @@ package com.dzeio.charts.axis
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF import android.graphics.Rect
import com.dzeio.charts.ChartViewInterface import com.dzeio.charts.ChartViewInterface
import com.dzeio.charts.utils.drawDottedLine
class YAxis( class YAxis(
private val view: ChartViewInterface private val view: ChartViewInterface
) : YAxisInterface { ) : YAxisInterface {
override var enabled = false override var enabled = true
override val textLabel = Paint().apply { override val textLabel = Paint().apply {
isAntiAlias = true isAntiAlias = true
color = Color.parseColor("#FC496D") color = Color.parseColor("#FC496D")
textSize = 30f 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 override var labelCount: Int = 3
private var min: Float? = null private var min: Float? = null
private var max: Float? = null private var max: Float? = null
private val rect = Rect()
override fun setYMin(yMin: Float?): YAxisInterface { override fun setYMin(yMin: Float?): YAxisInterface {
min = yMin min = yMin
return this 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 min = getYMin()
val max = getYMax() - min val max = getYMax() - min
val top = drawLocation.top val top = 0
val bottom = drawLocation.bottom val bottom = canvas.height.toFloat()
var maxWidth = 0f
val increment = (bottom - top) / labelCount val increment = (bottom - top) / labelCount
val valueIncrement = (max - min) / labelCount val valueIncrement = (max - min) / labelCount
for (index in 0 until 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( canvas.drawText(
(valueIncrement * (labelCount + 1)).toString(), text,
bottom - (index + 1) * increment, canvas.width - rect.width().toFloat(),
drawLocation.right, posY + rect.height() + 8f,
textLabel textLabel
) )
canvas.drawDottedLine(0f, posY, canvas.width.toFloat(), posY, 40f, linePaint)
} }
TODO("IDK if it works tbh") return maxWidth
} }
} }

View File

@ -2,7 +2,6 @@ package com.dzeio.charts.axis
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF
sealed interface YAxisInterface { sealed interface YAxisInterface {
@ -52,7 +51,14 @@ sealed interface YAxisInterface {
val textLabel: Paint 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
} }

View File

@ -1,10 +1,9 @@
package com.dzeio.charts.series package com.dzeio.charts.series
import android.graphics.Canvas import android.graphics.*
import android.graphics.Color import android.util.Log
import android.graphics.Paint
import android.graphics.RectF
import com.dzeio.charts.ChartView import com.dzeio.charts.ChartView
import com.dzeio.charts.utils.drawRoundRect
class BarSerie( class BarSerie(
private val view: ChartView private val view: ChartView
@ -19,6 +18,15 @@ class BarSerie(
color = Color.parseColor("#123456") 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) { override fun onDraw(canvas: Canvas, drawableSpace: RectF) {
val spacing = drawableSpace.width() / view.xAxis.displayCount / 10 val spacing = drawableSpace.width() / view.xAxis.displayCount / 10
val barWidth = drawableSpace.width() / view.xAxis.displayCount - spacing val barWidth = drawableSpace.width() / view.xAxis.displayCount - spacing
@ -30,38 +38,61 @@ class BarSerie(
for (entry in displayedEntries) { for (entry in displayedEntries) {
// calculated height in percent from 0 to 100 // calculated height in percent from 0 to 100
val height = (1 - entry.y / max) * drawableSpace.height() val top = (1 - entry.y / max) * drawableSpace.height()
// -1.945763981752553E-21 val posX = (view.xAxis.getPositionOnRect(entry, drawableSpace) - view.xAxis.getXOffset(drawableSpace)).toFloat()
// 2.103653925902835E-21
val posX = view.xAxis.getPositionOnRect(entry, drawableSpace) - view.xAxis.getXOffset(drawableSpace) - canvas.width
// Log.d(TAG, "gpor = ${view.xAxis.getPositionOnRect(entry, space)}, gxo = ${view.xAxis.getXOffset(space)}") // 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, "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: ${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( Log.d(
// TAG, """ TAG, """
// ${posX.toFloat()}, ${posX},
// $height, $top,
// ${(posX + barWidth).toFloat()}, ${(posX + barWidth).toFloat()},
// ${space.bottom}""".trimIndent() ${drawableSpace.bottom}""".trimIndent()
// ) )
canvas.drawRect( val right = (posX + barWidth).toFloat().coerceAtMost(drawableSpace.right)
posX.toFloat(),
height, if (posX > right) {
(posX + barWidth).toFloat(), continue
}
canvas.drawRoundRect(
posX,
top,
right,
drawableSpace.bottom, drawableSpace.bottom,
// 8f, 8f,
32f,
32f,
0f,
0f,
barPaint barPaint
) )
canvas.drawText( // handle text display
entry.y.toString(), val text = view.yAxis.onValueFormat(entry.y)
(posX + barWidth / 2).toFloat(),
drawableSpace.bottom / 2,
view.yAxis.textLabel.apply {
textAlign = Paint.Align.CENTER
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
) )
} }
} }

View File

@ -22,7 +22,7 @@ sealed class BaseSerie(
// -+ view.xAxis.increment = one out of display // -+ view.xAxis.increment = one out of display
val minX = view.xAxis.x - view.xAxis.increment val minX = view.xAxis.x - view.xAxis.increment
val maxX = 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 entries.filter {
return@filter it.x in minX..maxX return@filter it.x in minX..maxX

View File

@ -2,6 +2,7 @@ package com.dzeio.charts.utils
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF
import kotlin.math.sqrt import kotlin.math.sqrt
fun Canvas.drawDottedLine( fun Canvas.drawDottedLine(
@ -47,3 +48,51 @@ fun Canvas.drawDottedLine(
// total line length // 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)
}