package io.xdrm.lebonprix.anim import android.content.Context import android.content.res.AssetManager import android.content.res.Resources import android.graphics.* import android.support.v4.content.res.ResourcesCompat import android.util.Log import android.view.animation.Animation import android.view.animation.BounceInterpolator import android.view.animation.CycleInterpolator import android.view.animation.Transformation import android.widget.ImageView import io.xdrm.lebonprix.R import kotlin.math.round class ResultRangeAnimation( private val ctx: Context, private val target: ImageView, private val originalWidth: Int, private val originalHeight: Int ) : Animation() { private var width: Int = 1000 private var height: Int = 1000 private var bitmap : Bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) private var canvas : Canvas = Canvas(bitmap) private var progress: Float = 0F private val relativeSliderWidth = 0.75F private var w = 0F private var h = 0F // actual data to display private var size: Float = 0F private var min: Float = 0F private var avg: Float = 0F private var max: Float = 0F fun setData(_size: Int, _min: Float, _avg: Float, _max: Float){ require(_avg > _min); require(_avg < _max) size = _size.toFloat() min = _min; avg = _avg; max = _max } init { setSize(originalWidth, originalHeight) target.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> setSize(right-left, bottom-top) } } override fun start() { target.startAnimation(this) } override fun applyTransformation(interpolatedTime: Float, t: Transformation?) { super.applyTransformation(interpolatedTime, t) progress = interpolatedTime draw() } private fun setSize(_width: Int, _height: Int){ width = _width height = _height // unregister previous target.setImageBitmap(null) canvas.setBitmap(null) bitmap.recycle() // build new bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) canvas = Canvas(bitmap) target.setImageBitmap(bitmap) } private fun draw(){ canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR) w = width * 1F h = height * 0.6F drawSlider() drawAverage() target.setImageBitmap(bitmap) } private fun drawSlider(){ // params val sliderThickness = 5F val sliderDotRadius = 10F val relativeCaptionSize = 0.04F val relativeValuesSize = 0.04F val relativeCaptionDistance = 0.2F val relativeValuesDistance = 0.1F // preprocessed values val sliderWidth = w * relativeSliderWidth val xoffset = (w - sliderWidth) * 0.5F val captionsDistance = sliderDotRadius + h*relativeCaptionDistance val valuesDistance = sliderDotRadius + h*relativeValuesDistance val average = 0.5F + progress*( (avg-min)/(max-min) - 0.5F) val averageX = sliderWidth * average // val averageX = sliderWidth * (avg-min) / (max-min) // paints val sliderPaint = Paint() sliderPaint.style = Paint.Style.STROKE sliderPaint.strokeCap = Paint.Cap.ROUND sliderPaint.strokeWidth = sliderThickness sliderPaint.color = Color.WHITE val dotPaint = Paint() dotPaint.color = Color.WHITE val roboto = ResourcesCompat.getFont(ctx, R.font.roboto) val captionLeftPaint = Paint() captionLeftPaint.typeface = roboto captionLeftPaint.textAlign = Paint.Align.LEFT captionLeftPaint.color = ResourcesCompat.getColor(ctx.resources, R.color.soft_grey, null) captionLeftPaint.textSize = relativeCaptionSize*w val captionRightPaint = Paint() captionRightPaint.typeface = roboto captionRightPaint.textAlign = Paint.Align.RIGHT captionRightPaint.color = ResourcesCompat.getColor(ctx.resources, R.color.soft_grey, null) captionRightPaint.textSize = relativeCaptionSize*w val valuesLeftPaint = Paint() valuesLeftPaint.typeface = roboto valuesLeftPaint.textAlign = Paint.Align.LEFT valuesLeftPaint.color = Color.WHITE valuesLeftPaint.textSize = relativeValuesSize*w val valuesRightPaint = Paint() valuesRightPaint.typeface = roboto valuesRightPaint.textAlign = Paint.Align.RIGHT valuesRightPaint.color = Color.WHITE valuesRightPaint.textSize = relativeValuesSize*w // (1) draw slider val slider = Path() slider.moveTo(xoffset, h/2) slider.lineTo(xoffset+sliderWidth, h/2) canvas.drawPath(slider, sliderPaint) // (2) draw slider dots // canvas.drawCircle(xoffset, h/2, sliderDotRadius, dotPaint) // canvas.drawCircle(xoffset+sliderWidth, h/2, sliderDotRadius, dotPaint) canvas.drawCircle(xoffset+averageX, h/2, sliderDotRadius, dotPaint) // (3) draw min+max captions canvas.drawText("min", xoffset, h * 0.5F + captionsDistance, captionLeftPaint) canvas.drawText("max", xoffset+sliderWidth, h/2 + captionsDistance, captionRightPaint) // (4) draw min+max values canvas.drawText("${min}€", xoffset, h/2 - valuesDistance, valuesLeftPaint) canvas.drawText("${max}€", xoffset+sliderWidth, h/2 - valuesDistance, valuesRightPaint) } private fun drawAverage(){ val relativeSampleSize = 0.03F // params val relativeTriangleWidth = 0.04F val relativeTriangleHeight = 0.2F val relativeTooltipWidth = 0.2F val relativeTooltipHeight = 0.7F // preprocessed values val sliderWidth = w * relativeSliderWidth val xoffset = (w - sliderWidth) * 0.5F val yoffset = height - h // val averageX = sliderWidth * (avg-min) / (max-min) val average = 0.5F + progress*( (avg-min)/(max-min) - 0.5F) val averageX = sliderWidth * average val triangleWidth = relativeTriangleWidth * w val triangleHeight = relativeTriangleHeight * yoffset val tooltipWidth = relativeTooltipWidth * w val tooltipHeight = relativeTooltipHeight * yoffset // (1) Draw triangle val whitePaint = Paint() whitePaint.color = Color.WHITE whitePaint.flags = Paint.ANTI_ALIAS_FLAG val triangle = Path() triangle.moveTo(xoffset+averageX, yoffset) triangle.lineTo(xoffset+averageX-triangleWidth, yoffset + triangleHeight + 1F) // add 1 to overlap triangle.lineTo(xoffset+averageX+triangleWidth, yoffset + triangleHeight + 1F) canvas.drawPath(triangle, whitePaint) // (2) Draw tooltip background canvas.drawRoundRect( RectF( xoffset+averageX - tooltipWidth/2, yoffset + triangleHeight, xoffset+averageX + tooltipWidth/2, yoffset + triangleHeight + tooltipHeight), 10F, 10F, whitePaint) // (3) Draw sample size val sampleSizePaint = Paint() sampleSizePaint.typeface = ResourcesCompat.getFont(ctx, R.font.roboto) sampleSizePaint.textAlign = Paint.Align.CENTER sampleSizePaint.color = ResourcesCompat.getColor(ctx.resources, R.color.soft_grey, null) sampleSizePaint.textSize = relativeSampleSize*w sampleSizePaint.flags = Paint.ANTI_ALIAS_FLAG canvas.drawText("sur ${size.toInt()} articles", xoffset+averageX, yoffset + triangleHeight + tooltipHeight + relativeSampleSize*w, sampleSizePaint) // (4) Draw average text val roboto = ResourcesCompat.getFont(ctx, R.font.roboto) val averageTextPaint = Paint() averageTextPaint.typeface = roboto averageTextPaint.textAlign = Paint.Align.CENTER averageTextPaint.color = ResourcesCompat.getColor(ctx.resources, R.color.colorAccent, null) averageTextPaint.textSize = 50F canvas.drawText("${round((min+average*(max-min)) *10F)/10F}€", xoffset+averageX, yoffset+triangleHeight + tooltipHeight*0.6F, averageTextPaint) } }