PhilJay / MPAndroidChart

A powerful 🚀 Android chart view / graph view library, supporting line- bar- pie- radar- bubble- and candlestick charts as well as scaling, panning and animations.
Other
37.56k stars 9.01k forks source link

Add setter for custom LegendRenderer #4432

Open Phocacius opened 5 years ago

Phocacius commented 5 years ago

Is your feature request related to a problem? Please describe. I'm using a bar chart with a legend, where one of the bar colours is white. My problem was that the legend circle will be invisible on a white background. Since I have already overridden a ChartRenderer to achieve some custom behaviour I intented to do the same for the LegendRenderer. However, there's only a public getter, not a setter though for the LegendRenderer.

Describe the solution you'd like I'd like to have a simple setter Chart#setLegendRenderer to use custom or modified LegendRenderers.

Describe alternatives you've considered Using reflection is of course possible and this is my current solution However, this is not exactly clean code and also has a performance impact on Android. (Kotlin sample below)

fun Chart<*>.setCustomLegendRenderer() {
    val field = Chart::class.java.getDeclaredField("mLegendRenderer").apply { isAccessible = true }
    field.set(this, CustomLegendRenderer(viewPortHandler, legend))
} 

Additional context In case anyone's interested, what I was trying to do is add another (stroked) circle around the legend form, to make the circle visible. This is my custom renderer, that's achieving this:

class CustomLegendRenderer(viewPortHandler: ViewPortHandler, legend: Legend) : LegendRenderer(viewPortHandler, legend) {

    override fun drawForm(c: Canvas, x: Float, y: Float, entry: LegendEntry, legend: Legend) {
        if (entry.formColor == ColorTemplate.COLOR_SKIP || entry.formColor == ColorTemplate.COLOR_NONE || entry.formColor == 0) return

        val form: Legend.LegendForm = when (entry.form) {
            Legend.LegendForm.DEFAULT -> legend.form
            else -> entry.form
        }

        if (form == Legend.LegendForm.DEFAULT || form == Legend.LegendForm.CIRCLE) {
            drawFormCircle(c, x, y, entry, legend)
        } else {
            super.drawForm(c, x, y, entry, legend)
        }

    }

    private fun drawFormCircle(c: Canvas, x: Float, y: Float, entry: LegendEntry, legend: Legend) {
        mLegendFormPaint.color = entry.formColor
        mLegendFormPaint.style = Paint.Style.FILL

        val halfFormSize = 0.5f * Utils.convertDpToPixel(
                if (java.lang.Float.isNaN(entry.formSize)) legend.formSize else entry.formSize
        )

        c.drawCircle(x + halfFormSize, y, halfFormSize, mLegendFormPaint)

        if (ColorUtils.calculateLuminance(entry.formColor) > 0.5) {
            mLegendFormPaint.color = legend.textColor
            mLegendFormPaint.style = Paint.Style.STROKE
            c.drawCircle(x + halfFormSize, y, halfFormSize, mLegendFormPaint)
        }
    }
}
oliviadodge commented 5 years ago

I would also appreciate the option for setting a custom LegendRenderer.

Additionally: 1.) If the LegendEntry class had the option of setting a Drawable for the form, this would be useful. That way the legend can better show the user what the icons on the chart mean. 2.) If the legend is too big to fit nicely on one side of the chart (e.g. the label descriptions are too long), it would be nice to have option of setting another legend on a different side of the chart to contain overflow information.

aditya1711 commented 4 years ago

does this exist now?