mirror of
https://github.com/dzeiocom/OpenHealth.git
synced 2025-07-09 21:09:18 +00:00
feat: Add Custom Chart Library
This commit is contained in:
@ -0,0 +1,24 @@
|
||||
package com.dzeio.charts
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.dzeio.charts.test", appContext.packageName)
|
||||
}
|
||||
}
|
5
charts/src/main/AndroidManifest.xml
Normal file
5
charts/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.dzeio.charts">
|
||||
|
||||
</manifest>
|
199
charts/src/main/java/com/dzeio/charts/BarView.kt
Normal file
199
charts/src/main/java/com/dzeio/charts/BarView.kt
Normal file
@ -0,0 +1,199 @@
|
||||
package com.dzeio.charts
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import kotlin.math.abs
|
||||
|
||||
class BarView @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) :
|
||||
View(context, attrs) {
|
||||
|
||||
companion object {
|
||||
const val TAG = "DzeioCharts/BarView"
|
||||
}
|
||||
|
||||
/**
|
||||
* Nunber of entries displayed at the same time
|
||||
*/
|
||||
val numberOfEntries = 5
|
||||
|
||||
/**
|
||||
* Number of labels displayed at the same time
|
||||
*/
|
||||
val numberOfLabels = 3
|
||||
|
||||
/**
|
||||
* Spacing between entries
|
||||
*/
|
||||
val spacing = 22
|
||||
|
||||
/**
|
||||
* top margin from the canvas
|
||||
*/
|
||||
@Deprecated("Not needed anymore, Use the parent Padding/Margin")
|
||||
private val topMargin: Int = 5
|
||||
|
||||
private val textTopMargin = 5
|
||||
|
||||
private var barWidth: Int = 0
|
||||
|
||||
private val textColor = Color.parseColor("#9B9A9B")
|
||||
|
||||
private val foregroundColor = Color.parseColor("#FC496D")
|
||||
private val percentList: ArrayList<Float> = ArrayList()
|
||||
private var targetPercentList: ArrayList<Float> = ArrayList()
|
||||
private val textPaint: Paint = Paint().also {
|
||||
it.isAntiAlias = true
|
||||
it.color = textColor
|
||||
it.textSize = 25f
|
||||
it.textAlign = Paint.Align.CENTER
|
||||
}
|
||||
|
||||
private val fgPaint: Paint = Paint().also {
|
||||
it.isAntiAlias = true
|
||||
it.color = foregroundColor
|
||||
}
|
||||
private val rect: Rect = Rect()
|
||||
private var bottomTextDescent = 0
|
||||
private var bottomTextHeight = 0
|
||||
private var bottomTextList: ArrayList<String>? = ArrayList()
|
||||
private val animator: Runnable = object : Runnable {
|
||||
override fun run() {
|
||||
var needNewFrame = false
|
||||
for (i in targetPercentList.indices) {
|
||||
if (percentList[i] < targetPercentList[i]) {
|
||||
percentList[i] = percentList[i] + 0.02f
|
||||
needNewFrame = true
|
||||
} else if (percentList[i] > targetPercentList[i]) {
|
||||
percentList[i] = percentList[i] - 0.02f
|
||||
needNewFrame = true
|
||||
}
|
||||
if (abs(targetPercentList[i] - percentList[i]) < 0.02f) {
|
||||
percentList[i] = targetPercentList[i]
|
||||
}
|
||||
}
|
||||
if (needNewFrame) {
|
||||
postDelayed(this, 20)
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dataList will be reset when called is method.
|
||||
*
|
||||
* @param bottomStringList The String ArrayList in the bottom.
|
||||
*/
|
||||
fun setBottomTextList(bottomStringList: ArrayList<String>?) {
|
||||
barWidth = measuredWidth / numberOfEntries - spacing
|
||||
bottomTextList = bottomStringList
|
||||
val r = Rect()
|
||||
bottomTextDescent = 0
|
||||
for (s in bottomTextList!!) {
|
||||
textPaint.getTextBounds(s, 0, s.length, r)
|
||||
if (bottomTextHeight < r.height()) {
|
||||
bottomTextHeight = r.height()
|
||||
}
|
||||
Log.d(TAG, measuredWidth.toString())
|
||||
// if (autoSetWidth && barWidth < r.width()) {
|
||||
// barWidth = r.width()
|
||||
// }
|
||||
if (bottomTextDescent < abs(r.bottom)) {
|
||||
bottomTextDescent = abs(r.bottom)
|
||||
}
|
||||
}
|
||||
postInvalidate()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list The ArrayList of Integer with the range of [0-max].
|
||||
*/
|
||||
fun setDataList(list: ArrayList<Int>) {
|
||||
barWidth = measuredWidth / numberOfEntries - spacing
|
||||
// Calculate max
|
||||
val max = list.reduce { acc, i -> if (acc > i) return@reduce acc else return@reduce i }
|
||||
|
||||
targetPercentList = ArrayList()
|
||||
for (integer in list) {
|
||||
targetPercentList.add(1 - integer.toFloat() / max.toFloat())
|
||||
}
|
||||
|
||||
// Make sure percentList.size() == targetPercentList.size()
|
||||
if (percentList.isEmpty() || percentList.size < targetPercentList.size) {
|
||||
val temp = targetPercentList.size - percentList.size
|
||||
for (i in 0 until temp) {
|
||||
percentList.add(1f)
|
||||
}
|
||||
} else if (percentList.size > targetPercentList.size) {
|
||||
val temp = percentList.size - targetPercentList.size
|
||||
for (i in 0 until temp) {
|
||||
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")
|
||||
val right = (spacing + barWidth) * i
|
||||
val bottom = height - bottomTextHeight - textTopMargin
|
||||
val top = topMargin + ((bottom - topMargin) * percentList[i - 1])
|
||||
|
||||
rect.set(left, top.toInt(), right, bottom)
|
||||
|
||||
canvas.drawRect(rect, fgPaint)
|
||||
}
|
||||
}
|
||||
if (bottomTextList != null && !bottomTextList!!.isEmpty()) {
|
||||
var i = 1
|
||||
for (s in bottomTextList!!) {
|
||||
canvas.drawText(
|
||||
s,
|
||||
(spacing * i + barWidth * (i - 1) + barWidth / 2).toFloat(),
|
||||
(height - bottomTextDescent).toFloat(),
|
||||
textPaint
|
||||
)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val mViewWidth = measureWidth(widthMeasureSpec)
|
||||
val mViewHeight = measureHeight(heightMeasureSpec)
|
||||
setMeasuredDimension(mViewWidth, mViewHeight)
|
||||
}
|
||||
|
||||
private fun measureWidth(measureSpec: Int): Int {
|
||||
var preferred = 0
|
||||
if (bottomTextList != null) {
|
||||
preferred = bottomTextList!!.size * (barWidth + spacing)
|
||||
}
|
||||
return getMeasurement(measureSpec, preferred)
|
||||
}
|
||||
|
||||
private fun measureHeight(measureSpec: Int): Int {
|
||||
val preferred = 222
|
||||
return getMeasurement(measureSpec, preferred)
|
||||
}
|
||||
|
||||
private fun getMeasurement(measureSpec: Int, preferred: Int): Int {
|
||||
val specSize = MeasureSpec.getSize(measureSpec)
|
||||
val measurement = when (MeasureSpec.getMode(measureSpec)) {
|
||||
MeasureSpec.EXACTLY -> specSize
|
||||
MeasureSpec.AT_MOST -> Math.min(preferred, specSize)
|
||||
else -> preferred
|
||||
}
|
||||
return measurement
|
||||
}
|
||||
}
|
17
charts/src/test/java/com/dzeio/charts/ExampleUnitTest.kt
Normal file
17
charts/src/test/java/com/dzeio/charts/ExampleUnitTest.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package com.dzeio.charts
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user