From 39f6e7cbeffb94f8ef71fa846d0c50f38d6abeb1 Mon Sep 17 00:00:00 2001 From: Avior Date: Tue, 23 Aug 2022 00:59:10 +0200 Subject: [PATCH] feat(charts): Add back the XAxis/YAxis/Scrolling --- .../openhealth/ui/steps/StepsHomeFragment.kt | 56 +++--- .../main/java/com/dzeio/charts/ChartView.kt | 142 ++++++++++----- .../java/com/dzeio/charts/ChartView.kt.old | 166 ------------------ .../com/dzeio/charts/ChartViewInterface.kt | 9 +- .../src/main/java/com/dzeio/charts/Entry.kt | 3 + .../main/java/com/dzeio/charts/axis/XAxis.kt | 52 +++++- .../java/com/dzeio/charts/axis/XAxis.kt.old | 25 --- .../com/dzeio/charts/axis/XAxisInterface.kt | 43 +++++ .../main/java/com/dzeio/charts/axis/YAxis.kt | 29 +-- .../java/com/dzeio/charts/axis/YAxis.kt.old | 74 -------- .../com/dzeio/charts/axis/YAxisInterface.kt | 47 +++-- .../com/dzeio/charts/axis/YAxisPosition.kt | 5 + .../dzeio/charts/components/ChartScroll.kt | 3 + .../java/com/dzeio/charts/series/BarSerie.kt | 44 ++++- .../dzeio/charts/series/SerieAbstract.kt.old | 64 ------- .../com/dzeio/charts/series/SerieInterface.kt | 13 ++ .../com/dzeio/charts/utils/CanvasUtils.kt | 3 + 17 files changed, 331 insertions(+), 447 deletions(-) delete mode 100644 charts/src/main/java/com/dzeio/charts/ChartView.kt.old delete mode 100644 charts/src/main/java/com/dzeio/charts/axis/XAxis.kt.old delete mode 100644 charts/src/main/java/com/dzeio/charts/axis/YAxis.kt.old delete mode 100644 charts/src/main/java/com/dzeio/charts/series/SerieAbstract.kt.old 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 c819d4f..3559612 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 @@ -13,6 +13,9 @@ import com.dzeio.openhealth.core.BaseFragment import com.dzeio.openhealth.databinding.FragmentStepsHomeBinding import com.google.android.material.color.MaterialColors import dagger.hilt.android.AndroidEntryPoint +import java.text.DateFormat +import java.util.Date +import java.util.Locale @AndroidEntryPoint class StepsHomeFragment : @@ -61,10 +64,10 @@ class StepsHomeFragment : chart.apply { series = arrayListOf(serie) - debug = true +// debug = true yAxis.apply { - setYMin(0f) + setYMax(500f) textLabel.color = MaterialColors.getColor( requireView(), com.google.android.material.R.attr.colorOnPrimaryContainer @@ -79,27 +82,34 @@ class StepsHomeFragment : xAxis.apply { increment = 3600000.0 - displayCount = 168 -// displayCount = 24 +// displayCount = 168 + displayCount = 10 + textPaint.color = MaterialColors.getColor( + requireView(), + com.google.android.material.R.attr.colorOnPrimaryContainer + ) + textPaint.textSize = 32f + onValueFormat = onValueFormat@{ + val formatter = DateFormat.getDateTimeInstance( + DateFormat.SHORT, + DateFormat.SHORT, + Locale.getDefault() + ) + return@onValueFormat formatter.format(Date(it.toLong())) + } + } } viewModel.items.observe(viewLifecycleOwner) { list -> adapter.set(list) - chart.debug = true - // chart.animation.enabled = false // chart.animation.refreshRate = 60 // chart.animation.duration = 300 // chart.scroller.zoomEnabled = false -// chart.xAxis.labels.color = MaterialColors.getColor( -// requireView(), -// com.google.android.material.R.attr.colorOnBackground -// ) - // chart.xAxis.labels.size = 32f serie.entries = list.reversed().map { @@ -108,32 +118,8 @@ class StepsHomeFragment : chart.xAxis.x = serie.entries.first().x -// chart.xAxis.onValueFormat = onValueFormat@{ -// val formatter = DateFormat.getDateTimeInstance( -// DateFormat.SHORT, -// DateFormat.SHORT, -// Locale.getDefault() -// ) -// return@onValueFormat formatter.format(Date(it.toLong())) -// } chart.refresh() } - -// val scrollView = requireActivity().findViewById(R.id.scrollView) -// var scrollEnabled = false -// scrollView.setOnTouchListener { view, _ -> -// view.performClick() -// if (scrollEnabled) { -// } else { -// return@setOnTouchListener !scrollEnabled -// } -// return@setOnTouchListener true -// } - -// binding.chart.setOnToggleScroll { -// Log.d(TAG, it.toString()) -// scrollEnabled = it -// } } } diff --git a/charts/src/main/java/com/dzeio/charts/ChartView.kt b/charts/src/main/java/com/dzeio/charts/ChartView.kt index 2334058..f48ae93 100644 --- a/charts/src/main/java/com/dzeio/charts/ChartView.kt +++ b/charts/src/main/java/com/dzeio/charts/ChartView.kt @@ -1,12 +1,12 @@ package com.dzeio.charts +import android.annotation.SuppressLint import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.RectF import android.util.AttributeSet -import android.util.Log import android.view.MotionEvent import android.view.View import com.dzeio.charts.axis.XAxis @@ -21,14 +21,6 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet const val TAG = "Charts/ChartView" } - private val rect = RectF() - - private val debugStrokePaint = Paint().apply { - style = Paint.Style.STROKE - strokeWidth = 8f - color = Color.parseColor("#654321") - } - override var debug: Boolean = false override val xAxis = XAxis(this) @@ -37,43 +29,13 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet override var series: ArrayList = arrayListOf() - override fun refresh() { - invalidate() - } + override var padding: Float = 8f - override fun onDraw(canvas: Canvas) { - - if (debug) { - // draw corners - canvas.drawRect(rect.apply { - set(8f, 8f, width - 8f, height - 8f) - }, debugStrokePaint) - } - - // right distance from the yAxis - val rightDistance = yAxis.onDraw(canvas) - - // chart draw rectangle - rect.apply { - set(0f, 8f, width.toFloat() - 16f - rightDistance, height.toFloat() - 16f) - } - - for (serie in series) { - serie.onDraw(canvas, rect) - } - super.onDraw(canvas) - } - - override fun onTouchEvent(event: MotionEvent): Boolean { - performClick() - return scroller.onTouchEvent(event) - } - - val scroller = ChartScroll(this).apply { + private val scroller = ChartScroll(this).apply { var lastMovement = 0.0 setOnChartMoved { movementX, _ -> - Log.d(TAG, "scrolled: ${(movementX - lastMovement) * (xAxis.increment / 10)}") +// Log.d(TAG, "scrolled: ${(movementX - lastMovement) * (xAxis.increment / 10)}") xAxis.x = xAxis.x + (movementX - lastMovement) * (xAxis.increment / 10) lastMovement = movementX.toDouble() refresh() @@ -84,4 +46,98 @@ class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet // refresh() // } } -} \ No newline at end of file + +// val animator: Runnable = object : Runnable { +// override fun run() { +// var needNewFrame = false +// for (serie in series) { +// val result = serie.onUpdate() +// if (result) { +// needNewFrame = true +// } +// } +// if (needNewFrame) { +// postDelayed(this, animation.getDelay().toLong()) +// } +// invalidate() +// } +// } + + // rect used for calculations + private val rect = RectF() + + // stroke used while in debug + private val debugStrokePaint = Paint().apply { + style = Paint.Style.STROKE + strokeWidth = 8f + color = Color.parseColor("#654321") + } + + override fun refresh() { + // run Axis logics + xAxis.refresh() + yAxis.refresh() + + // run series logic + for (serie in series) { + serie.refresh() + } + + // invalidate the view + invalidate() +// removeCallbacks(animator) +// post(animator) + } + + override fun onDraw(canvas: Canvas) { + + // don't draw anything if everything is empty + if (series.isEmpty() || series.maxOf { it.entries.size } == 0) { + super.onDraw(canvas) + return + } + + if (debug) { + // draw corners + canvas.drawRect(rect.apply { + set( + padding / 2, + padding / 2, + width.toFloat() - padding / 2, + height.toFloat() - padding / 2 + ) + }, debugStrokePaint) + } + + + val bottom = xAxis.onDraw(canvas, rect.apply { + set(padding, 0f, width.toFloat() - padding, height.toFloat() - padding) + }) + + // right distance from the yAxis + val rightDistance = yAxis.onDraw(canvas, rect.apply { + set(padding, padding, width.toFloat() - padding, height.toFloat() - bottom - padding) + }) + + // chart draw rectangle + rect.apply { + set( + padding, + padding, + width.toFloat() - padding - rightDistance, + height - bottom - padding + ) + } + + for (serie in series) { + serie.onDraw(canvas, rect) + } + super.onDraw(canvas) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + performClick() + return scroller.onTouchEvent(event) + } +} diff --git a/charts/src/main/java/com/dzeio/charts/ChartView.kt.old b/charts/src/main/java/com/dzeio/charts/ChartView.kt.old deleted file mode 100644 index d87ccf4..0000000 --- a/charts/src/main/java/com/dzeio/charts/ChartView.kt.old +++ /dev/null @@ -1,166 +0,0 @@ -package com.dzeio.charts - -import android.content.Context -import android.graphics.Canvas -import android.graphics.Color -import android.graphics.Paint -import android.graphics.RectF -import android.util.AttributeSet -import android.util.Log -import android.view.MotionEvent -import android.view.View -import com.dzeio.charts.axis.XAxis -import com.dzeio.charts.axis.YAxis -import com.dzeio.charts.components.ChartScroll -import com.dzeio.charts.series.SerieAbstract -import kotlin.math.max -import kotlin.math.min - -class ChartView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) : - View(context, attrs) { - - companion object { - const val TAG = "DzeioCharts/ChartView" - } - - override var debug = false - - override val xAxis = XAxis() - - override val yAxis = YAxis(this) - - override val animation = Animation() - - override val scroller = ChartScroll(this).apply { - setOnChartMoved { movementX, _ -> -// Log.d(TAG, "scrolled: $movementX") - movementOffset = movementX / 100 - refresh() - } - setOnZoomChanged { - Log.d(TAG, "New Zoom: $it") - zoom = (it * 1.2).toFloat() - refresh() - } - } - - override val animator: Runnable = object : Runnable { - override fun run() { - var needNewFrame = false - for (serie in series) { - val result = serie.onUpdate() - if (result) { - needNewFrame = true - } - } - if (needNewFrame) { - postDelayed(this, animation.getDelay().toLong()) - } - invalidate() - } - } - - /** - * global padding - */ - override var padding: Float = 8f - - override var series: ArrayList = arrayListOf() - set(value) { - for (serie in value) { - serie.view = this - } - field = value - } - - /** - * Number of entries displayed at the same time - */ - override var zoom = 100f - - override var movementOffset: Float = 0f - - override val rectF = RectF() - override val otherUseRectF = RectF() - - override fun refresh() { - for (serie in series) { - serie.prepareData() - } - rectF.set( - padding, - padding, - measuredWidth - padding - yAxis.getWidth() - padding, - height - padding - ) - - removeCallbacks(animator) - post(animator) - } - - override val fgPaint: Paint = Paint().also { - it.isAntiAlias = true - it.color = Color.parseColor("#123456") - } - - override fun onDraw(canvas: Canvas) { - - if (yAxis.legendEnabled) { - yAxis.display(canvas, measuredWidth, height) - } - - for (serie in series) { - serie.displayData(canvas, rectF) - } -// canvas.drawRect( -// measuredWidth - padding - yAxis.getWidth(), -// 0f, -// measuredWidth - padding, -// height - padding, -// fgPaint -// ) - super.onDraw(canvas) - } - - override fun onTouchEvent(event: MotionEvent): Boolean { - performClick() - return scroller.onTouchEvent(event) - } - - override fun getXOffset(): Int { -// Log.d( -// TAG, -// "baseOffset: ${xAxis.baseOffset}, mOffset: $movementOffset = ${xAxis.baseOffset + movementOffset}" -// ) -// Log.d( -// TAG, -// "longestOffset: ${longestSerie()}, displayedEntries: ${getDisplayedEntries()} = ${longestSerie() - getDisplayedEntries()}" -// ) - return min( - max(0f, xAxis.baseOffset + movementOffset).toInt(), - max(0, getCalculatedMax() - getDisplayedEntries()) - ) - } - - override fun getDisplayedEntries(): Int { -// Log.d(TAG, "Number of entries displayed ${list.size}, ${xAxis.entriesDisplayed} + (($zoom - 100) * 10) = ${xAxis.entriesDisplayed + ((zoom - 100) * 10).toInt()}") - return max(0, xAxis.entriesDisplayed + ((zoom - 100) * 10).toInt()) - } - - override fun getCalculatedMax(): Int { - var size = 0 - for (serie in series) { - if (serie.datas.size > size) size = serie.datas.size - } - return size - } - - override fun getXMax(displayedOnly: Boolean): Float { - var max = 0f - for (serie in series) { - val res = serie.getYMax(displayedOnly) - if (max < res) max = res - } - return max - } -} diff --git a/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt b/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt index 9abc222..0bd97cf 100644 --- a/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt +++ b/charts/src/main/java/com/dzeio/charts/ChartViewInterface.kt @@ -13,6 +13,11 @@ interface ChartViewInterface { */ var debug: Boolean + /** + * the padding inside the view + */ + var padding: Float + /** * Hold metadata about the X axis */ @@ -29,7 +34,9 @@ interface ChartViewInterface { var series: ArrayList /** - * refresh the chart + * refresh and run pre-display logic the chart + * + * this function should be run if you change parameters in the view */ fun refresh() } \ 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 index 1a46750..13c74a2 100644 --- a/charts/src/main/java/com/dzeio/charts/Entry.kt +++ b/charts/src/main/java/com/dzeio/charts/Entry.kt @@ -1,5 +1,8 @@ package com.dzeio.charts +/** + * A Base entry for any charts + */ data class Entry( val x: Double, val y: Float diff --git a/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt b/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt index bddad9e..bc2754e 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt @@ -1,5 +1,9 @@ package com.dzeio.charts.axis +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect import android.graphics.RectF import com.dzeio.charts.ChartViewInterface import com.dzeio.charts.Entry @@ -23,9 +27,20 @@ class XAxis( field = value } + + override var enabled = true override var increment: Double = 1.0 override var displayCount: Int = 10 - override var labelCount: Int = 3 + override var labelCount: Int = 2 + + override val textPaint = Paint().apply { + isAntiAlias = true + color = Color.parseColor("#FC496D") + textSize = 30f + textAlign = Paint.Align.LEFT + } + + private val rect = Rect() override fun getPositionOnRect(entry: Entry, rect: RectF): Double { return translatePositionToRect(entry.x, rect) @@ -52,5 +67,40 @@ class XAxis( } } + var onValueFormat: (value: Double) -> String = { it -> it.toString() } + override fun onDraw(canvas: Canvas, space: RectF): Float { + if (!enabled) { + return 0f + } + + var maxHeight = 0f + + val graphIncrement = space.width() / (labelCount - 1) + val valueIncrement = (displayCount * increment / (labelCount - 1)).toDouble() + for (index in 0 until labelCount) { + val text = onValueFormat(x + valueIncrement * index) + textPaint.getTextBounds(text, 0, text.length, rect) + maxHeight = maxHeight.coerceAtLeast(rect.height().toFloat() + 1) + + var xPos = space.left + graphIncrement * index + + if (xPos + rect.width() > space.right) { + xPos = space.right - rect.width() + } + + + canvas.drawText( + text, + xPos, + space.bottom, + textPaint + ) + } + return maxHeight + 32f + } + + override fun refresh() { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt.old b/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt.old deleted file mode 100644 index d44c5d8..0000000 --- a/charts/src/main/java/com/dzeio/charts/axis/XAxis.kt.old +++ /dev/null @@ -1,25 +0,0 @@ -package com.dzeio.charts.axis - -import com.dzeio.charts.XAxisLabels - -class XAxis { - - var max: T? = null - var min: T? = null - - val labels = XAxisLabels() - - /** - * Number of entries displayed in the chart at the same time - */ - var entriesDisplayed = 5 - - /** - * Offset in the list - */ - var baseOffset = 0 - - var onValueFormat: (it: T) -> String = onValueFormat@{ - return@onValueFormat it.toString() - } -} diff --git a/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt b/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt index 08914e5..b4e7716 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/XAxisInterface.kt @@ -1,10 +1,17 @@ package com.dzeio.charts.axis +import android.graphics.Canvas +import android.graphics.Paint import android.graphics.RectF import com.dzeio.charts.Entry sealed interface XAxisInterface { + /** + * enable/disable the display of the xAxis + */ + var enabled: Boolean + /** * set X position */ @@ -15,6 +22,11 @@ sealed interface XAxisInterface { */ var increment: Double + /** + * text Paint + */ + val textPaint: Paint + /** * indicate the max number of entries are displayed */ @@ -25,11 +37,42 @@ sealed interface XAxisInterface { */ var labelCount: Int + /** + * run when manually refreshing the system + * + * this is where the pre-logic is handled to make [onDraw] quicker + */ + fun refresh() + + /** + * get the entry position on the rect + * + * @return the left side of the position of the entry + */ fun getPositionOnRect(entry: Entry, rect: RectF): Double + /** + * get the graph offset for X (kinda like [getPositionOnRect]) + */ fun getXOffset(rect: RectF): Double + /** + * get the maximum the X can get to + */ fun getXMax(): Double + /** + * get the minimum the X can get to + */ fun getXMin(): Double + + /** + * onDraw event that will draw the XAxis + * + * @param canvas the canvas to draw on + * @param space the space where it is allowed to draw + * + * @return the final height of the XAxis + */ + fun onDraw(canvas: Canvas, space: RectF): Float } \ No newline at end of file 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 f3a5f66..2a1587d 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt @@ -4,8 +4,8 @@ import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Rect +import android.graphics.RectF import com.dzeio.charts.ChartViewInterface -import com.dzeio.charts.utils.drawDottedLine class YAxis( private val view: ChartViewInterface @@ -25,11 +25,11 @@ class YAxis( color = Color.BLUE } - var onValueFormat: (value: Float) -> String = { it -> it.toString()} + var onValueFormat: (value: Float) -> String = { it -> it.toString() } - override var labelCount: Int = 3 + override var labelCount = 5 - private var min: Float? = null + private var min: Float? = 0f private var max: Float? = null private val rect = Rect() @@ -76,14 +76,14 @@ class YAxis( } } - override fun onDraw(canvas: Canvas): Float { + override fun onDraw(canvas: Canvas, space: RectF): Float { if (!enabled) { return 0f } val min = getYMin() val max = getYMax() - min - val top = 0 - val bottom = canvas.height.toFloat() + val top = space.top + val bottom = space.bottom var maxWidth = 0f val increment = (bottom - top) / labelCount @@ -97,13 +97,18 @@ class YAxis( canvas.drawText( text, - canvas.width - rect.width().toFloat(), - posY + rect.height() + 8f, + space.width() - rect.width().toFloat(), + (posY + rect.height() / 2).coerceAtLeast(rect.height().toFloat()), textLabel ) - canvas.drawDottedLine(0f, posY, canvas.width.toFloat(), posY, 40f, linePaint) +// canvas.drawDottedLine(0f, posY, canvas.width.toFloat(), posY, 40f, linePaint) + canvas.drawLine(space.left, posY, space.right - maxWidth - 32f, posY, linePaint) } - return maxWidth + return maxWidth + 32f } -} \ No newline at end of file + + override fun refresh() { + TODO("Not yet implemented") + } +} diff --git a/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt.old b/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt.old deleted file mode 100644 index 2bd9822..0000000 --- a/charts/src/main/java/com/dzeio/charts/axis/YAxis.kt.old +++ /dev/null @@ -1,74 +0,0 @@ -package com.dzeio.charts.axis - -import android.graphics.Canvas -import android.graphics.Color -import android.graphics.Paint -import android.graphics.Rect -import androidx.annotation.ColorInt -import com.dzeio.charts.ChartView -import com.dzeio.charts.utils.drawDottedLine - -class YAxis( - private val chartView: ChartView -) { - var max: T? = null - var min: T? = null - - /** - * Number of labels displayed on the sidebar - */ - var labelCount: Int = 4 - - @ColorInt - var color = Color.parseColor("#FC496D") - - var textPaint: Paint = Paint().also { - it.isAntiAlias = true - it.color = color - it.textSize = 30f - it.textAlign = Paint.Align.RIGHT - } - - var linePaint = Paint().apply { - isAntiAlias = true - } - - var legendEnabled = true - - private val rect: Rect = Rect() - - fun getWidth(): Int { - var maxWidth = 0 - val max = chartView.getXMax(true) - val vIncrement = max / labelCount - for (i in 0 until labelCount) { - val text = onValueFormat(vIncrement * (labelCount - i), true) - textPaint.getTextBounds(text, 0, text.length, rect) - if (rect.width() > maxWidth) maxWidth = rect.width() - } - return maxWidth + chartView.padding.toInt() - } - - /** - * Function to display the YAxis sidebar on the right - * - * it migh also display content over the Graph - */ - fun display(canvas: Canvas, width: Int, height: Int) { - val max = chartView.getXMax(true) - val increment = (height - chartView.padding * 2) / labelCount - val vIncrement = max / labelCount - for (i in 0 until labelCount) { - val text = onValueFormat(vIncrement * (labelCount - i), true) - textPaint.getTextBounds(text, 0, text.length, rect) - val posY = increment * i.toFloat() - canvas.drawDottedLine(0f, posY + chartView.padding, width - rect.width().toFloat() - chartView.padding, posY, 40f, linePaint) - canvas.drawText(text, - width.toFloat() - chartView.padding, posY + chartView.padding, textPaint) -// canvas.drawDottedLine(0f, posY, measuredWidth.toFloat(), posY, 10f, linePaint) - } - } - - var onValueFormat: (value: Float, shortVersion: Boolean) -> String = { it, _ -> it.toString() } - -} 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 0617f5b..172b9c4 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/YAxisInterface.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/YAxisInterface.kt @@ -2,6 +2,7 @@ package com.dzeio.charts.axis import android.graphics.Canvas import android.graphics.Paint +import android.graphics.RectF sealed interface YAxisInterface { @@ -10,6 +11,30 @@ sealed interface YAxisInterface { */ var enabled: Boolean + /** + * get/set the number of label of this Y axis + * + * the first/last labels are at the bottom/top of the chart + */ + var labelCount: Int + + /** + * text label paint + */ + val textLabel: Paint + + /** + * paint for the lines + */ + val linePaint: Paint + + /** + * run when manually refreshing the system + * + * this is where the pre-logic is handled to make [onDraw] quicker + */ + fun refresh() + /** * override Y minimum * @@ -38,27 +63,13 @@ sealed interface YAxisInterface { */ fun getYMin(): Float - /** - * get/set the number of label of this Y axis - * - * the first/last labels are at the bottom/top of the chart - */ - var labelCount: Int - - /** - * text label paint - */ - val textLabel: Paint - - /** - * paint for the dotted line - */ - val linePaint: Paint - /** * function that draw our legend * + * @param canvas the canvas to draw on + * @param space the space where it is allowed to draw on + * * @return the width of the sidebar */ - fun onDraw(canvas: Canvas): Float + fun onDraw(canvas: Canvas, space: RectF): Float } \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/axis/YAxisPosition.kt b/charts/src/main/java/com/dzeio/charts/axis/YAxisPosition.kt index 2a75b3c..d134c6d 100644 --- a/charts/src/main/java/com/dzeio/charts/axis/YAxisPosition.kt +++ b/charts/src/main/java/com/dzeio/charts/axis/YAxisPosition.kt @@ -1,5 +1,10 @@ package com.dzeio.charts.axis +/** + * CURRENTLY UNUSED + * + * declare where the YAxis for the graph will be + */ enum class YAxisPosition { LEFT, RIGHT diff --git a/charts/src/main/java/com/dzeio/charts/components/ChartScroll.kt b/charts/src/main/java/com/dzeio/charts/components/ChartScroll.kt index 7e7850f..38e1b9f 100644 --- a/charts/src/main/java/com/dzeio/charts/components/ChartScroll.kt +++ b/charts/src/main/java/com/dzeio/charts/components/ChartScroll.kt @@ -5,6 +5,9 @@ import android.view.MotionEvent.INVALID_POINTER_ID import android.view.ScaleGestureDetector import android.view.View +/** + * Class handling the scroll/zoom for the library + */ class ChartScroll(view: View) { /** 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 0cf67fe..1fea280 100644 --- a/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt +++ b/charts/src/main/java/com/dzeio/charts/series/BarSerie.kt @@ -1,6 +1,10 @@ package com.dzeio.charts.series -import android.graphics.* +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.RectF import android.util.Log import com.dzeio.charts.ChartView import com.dzeio.charts.utils.drawRoundRect @@ -13,6 +17,10 @@ class BarSerie( const val TAG = "Charts/BarSerie" } + init { + view.series.add(this) + } + val barPaint = Paint().apply { isAntiAlias = true color = Color.parseColor("#123456") @@ -38,8 +46,8 @@ class BarSerie( for (entry in displayedEntries) { // calculated height in percent from 0 to 100 - val top = (1 - entry.y / max) * drawableSpace.height() - val posX = (view.xAxis.getPositionOnRect(entry, drawableSpace) - view.xAxis.getXOffset(drawableSpace)).toFloat() + val top = (1 - entry.y / max) * drawableSpace.height() + drawableSpace.top + var posX = drawableSpace.left + (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)}") @@ -48,14 +56,20 @@ class BarSerie( TAG, """ ${posX}, $top, - ${(posX + barWidth).toFloat()}, + ${(posX + barWidth)}, ${drawableSpace.bottom}""".trimIndent() ) - val right = (posX + barWidth).toFloat().coerceAtMost(drawableSpace.right) + val right = (posX + barWidth).coerceAtMost(drawableSpace.right) if (posX > right) { continue + } else if (posX < drawableSpace.left) { + posX = drawableSpace.left + } + + if (right < drawableSpace.left) { + continue } canvas.drawRoundRect( @@ -76,9 +90,14 @@ class BarSerie( textPaint.getTextBounds(text, 0, text.length, rect) - val textLeft = (posX + barWidth / 2).toFloat() + val textLeft = (posX + barWidth / 2) - if (textLeft + rect.width() / 2 > right) { + if ( + // handle right side + textLeft + rect.width() / 2 > right || + // handle left sie + textLeft - rect.width() / 2 < drawableSpace.left + ) { continue } @@ -86,14 +105,23 @@ class BarSerie( rect.height() + 40f < drawableSpace.bottom - top && rect.width() < barWidth + var textY = if (doDisplayIn) top + rect.height() + 20f else top - 20f + + if (textY < 0) { + textY = drawableSpace.top + rect.height() + } canvas.drawText( text, textLeft, - if (doDisplayIn) top + rect.height() + 20f else top - 20f, + textY, textPaint ) } } + + override fun refresh() { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/charts/src/main/java/com/dzeio/charts/series/SerieAbstract.kt.old b/charts/src/main/java/com/dzeio/charts/series/SerieAbstract.kt.old deleted file mode 100644 index 839d3c3..0000000 --- a/charts/src/main/java/com/dzeio/charts/series/SerieAbstract.kt.old +++ /dev/null @@ -1,64 +0,0 @@ -package com.dzeio.charts.series - -import android.graphics.Canvas -import android.graphics.RectF -import com.dzeio.charts.ChartView -import com.dzeio.charts.Entry -import kotlin.math.min - -abstract class SerieAbstract { - - var datas: ArrayList = arrayListOf() - - lateinit var view: ChartView - - /** - * get Serie Y max - */ - fun getYMax(displayedOnly: Boolean = false): Float { - var max = Float.MIN_VALUE - val localDatas = if (displayedOnly) getDisplayedEntries() else datas - for (data in localDatas) { - if (max < data.y) max = data.y - } - return max - } - - - /** - * get Serie Y min - */ - fun getYMin(displayedOnly: Boolean = false): Float { - var min = Float.MAX_VALUE - val localDatas = if (displayedOnly) getDisplayedEntries() else datas - for (data in localDatas) { - if (min > data.y) min = data.y - } - return min - } - - /** - * Animation updates - */ - abstract fun onUpdate(): Boolean - - /** - * Function to prepare for an update - */ - abstract fun prepareData() - - /** - * Function to display data on the graph - * - * @param canvas the canvas to draw on - * @param rect the rectangle in which you have to draw data - */ - abstract fun displayData(canvas: Canvas, rect: RectF) - - protected fun getDisplayedEntries(): MutableList { - return datas.subList( - view.getXOffset(), - min(datas.size, view.getDisplayedEntries() + view.getXOffset()) - ) - } -} diff --git a/charts/src/main/java/com/dzeio/charts/series/SerieInterface.kt b/charts/src/main/java/com/dzeio/charts/series/SerieInterface.kt index 887743d..e018dfe 100644 --- a/charts/src/main/java/com/dzeio/charts/series/SerieInterface.kt +++ b/charts/src/main/java/com/dzeio/charts/series/SerieInterface.kt @@ -24,5 +24,18 @@ sealed interface SerieInterface { */ var entries: ArrayList + /** + * function that display the graph + * + * @param canvas the canvas to draw on + * @param drawableSpace the space you are allowed to draw on + */ fun onDraw(canvas: Canvas, drawableSpace: RectF) + + /** + * run when manually refreshing the system + * + * this is where the pre-logic is handled to make [onDraw] quicker + */ + fun refresh() } \ No newline at end of file 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 337d8d3..4f053fd 100644 --- a/charts/src/main/java/com/dzeio/charts/utils/CanvasUtils.kt +++ b/charts/src/main/java/com/dzeio/charts/utils/CanvasUtils.kt @@ -5,6 +5,9 @@ import android.graphics.Paint import android.graphics.RectF import kotlin.math.sqrt +/** + * draw a dotted line + */ fun Canvas.drawDottedLine( startX: Float, startY: Float,