MPAndroidChart:在条形图内添加自定义图像 [英] MPAndroidChart: add custom image inside bars

查看:206
本文介绍了MPAndroidChart:在条形图内添加自定义图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用



如果栏值> =一个目标值,例如50,那么我想在栏内添加一个星形图像。



任何人都可以帮我定制BarChart吗?

解决方案

为了获得我们酒吧内的明星形象,我们需要创建自定义渲染器。因为我们的条形图使用 BarChartRenderer ,所以我们将首先创建子类并为图像添加一个参数:

  public class ImageBarChartRenderer extends BarChartRenderer {

private final Bitmap barImage;
$ b $ public ImageBarChartRenderer(BarDataProvider图表,ChartAnimator动画师,ViewPortHandler viewPortHandler,位图barImage){
super(图表,动画师,viewPortHandler);
this.barImage = barImage;



$ b $ p
$ b

如果我们检查 BarChartRenderer 我们可以看到它调用了名为 drawData 的方法,然后迭代每个DataSet并调用 drawDataSet drawDataSet 是动作发生的地方:它正在绘制阴影和条形图。这是一个适当的地方添加逻辑来绘制额外的图像,所以让我们添加一个调用方法来绘制我们的图像:

  @Override 
protected void drawDataSet(Canvas c,IBarDataSet dataSet,int index){
super.drawDataSet(c,dataSet,index);
drawBarImages(c,dataSet,index);

$ / code>

我们现在需要一个方法来遍历DataSet并绘制星形图像。将作为模板的适当方法是 drawValues 所以让我们复制并更改它,以便绘制图像而不是文本。理解这一点的关键是看BarBuffer是如何工作的。 BarBuffer为给定条目在 j j + 1 上保留屏幕(像素)坐标>, j + 2 j + 3 。为了澄清, j 是左边的x坐标, j + 1 是顶部y坐标,依此类推,直到x j + 3 的x坐标。我们将这些变量提取到变量中以便于理解:

  protected void drawBarImages(Canvas c,IBarDataSet dataSet,int index ){
BarBuffer buffer = mBarBuffers [index];

向左浮动; //避免在循环中分配
float right;
浮动顶部;
浮动底部;

for(int j = 0; j left = buffer.buffer [j];
right = buffer.buffer [j + 2];
top = buffer.buffer [j + 1];
bottom = buffer.buffer [j + 3];

float x =(left + right)/ 2f;

if(!mViewPortHandler.isInBoundsRight(x))
break;

if(!mViewPortHandler.isInBoundsY(top)
||!mViewPortHandler.isInBoundsLeft(x))
continue;

BarEntry entry = dataSet.getEntryForIndex(j / 4);
float val = entry.getY();

if(val> 50){
drawStar(c,barImage,x,top);
}
}
}

以下是如何使用渲染器:

 位图starBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.star); 
mChart.setRenderer(new ImageBarChartRenderer(mChart,mChart.getAnimator(),mChart.getViewPortHandler(),starBitmap));

渲染器的最后一步是添加逻辑来缩放位图并正确定位。这是自定义渲染器的最后一个概念验证:

  package com.xxmassdeveloper.mpchartexample; 

导入android.graphics.Bitmap;
导入android.graphics.Canvas;

import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.buffer.BarBuffer;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.renderer.BarChartRenderer;
import com.github.mikephil.charting.utils.ViewPortHandler;

/ **
*由David于29/12/2016创建。
* /

public class ImageBarChartRenderer extends BarChartRenderer {

private final Bitmap barImage;
$ b $ public ImageBarChartRenderer(BarDataProvider图表,ChartAnimator动画师,ViewPortHandler viewPortHandler,位图barImage){
super(图表,动画师,viewPortHandler);
this.barImage = barImage;
}

@Override
public void drawData(Canvas c){
super.drawData(c);

$ b @Override
protected void drawDataSet(Canvas c,IBarDataSet dataSet,int index){
super.drawDataSet(c,dataSet,index);
drawBarImages(c,dataSet,index);
}

protected void drawBarImages(Canvas c,IBarDataSet dataSet,int index){
BarBuffer buffer = mBarBuffers [index];

向左浮动; //避免在循环中分配
float right;
浮动顶部;
浮动底部;

最终位图scaledBarImage = scaleBarImage(buffer);

int starWidth = scaledBarImage.getWidth();
int starOffset = starWidth / 2;

for(int j = 0; j left = buffer.buffer [j];
right = buffer.buffer [j + 2];
top = buffer.buffer [j + 1];
bottom = buffer.buffer [j + 3];

float x =(left + right)/ 2f;

if(!mViewPortHandler.isInBoundsRight(x))
break;

if(!mViewPortHandler.isInBoundsY(top)
||!mViewPortHandler.isInBoundsLeft(x))
continue;

BarEntry entry = dataSet.getEntryForIndex(j / 4);
float val = entry.getY();

if(val> 50){
drawImage(c,scaledBarImage,x - starOffset,top);



$ b私有位图scaleBarImage(BarBuffer缓冲区){
float firstLeft = buffer.buffer [0];
float firstRight = buffer.buffer [2];
int firstWidth =(int)Math.ceil(firstRight - firstLeft);
返回Bitmap.createScaledBitmap(barImage,firstWidth,firstWidth,false);

$ b $ protected void drawImage(Canvas c,Bitmap image,float x,float y){
if(image!= null){
c.drawBitmap(图像,x,y,null);
}
}
}

这里有一个截图 - 你可以看到超过50的值有明星:


I am using MPAndroidChart and I want to show a custom drawable inside this CombinedChart like in below image:

If bar value is >= a goal value, say, 50, then I would like to add a star image inside the bar.

Can any one help me for customise the BarChart?

解决方案

To get the star image inside our bars, we will need to create a custom renderer. Because our bar chart uses BarChartRenderer we will subclass this first and add a parameter for our image:

public class ImageBarChartRenderer extends BarChartRenderer {

    private final Bitmap barImage;

    public ImageBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, Bitmap barImage) {
        super(chart, animator, viewPortHandler);
        this.barImage = barImage;
    }

If we inspect the source for BarChartRenderer we can see that it calls the method called drawData and then iterates through each DataSet and calls drawDataSet. drawDataSet is where the action is happening: it's drawing the shadows and the bars. It's an appropriate place to add logic to draw an extra like images, so let's add a call to a method to draw our images there:

    @Override
    protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {
        super.drawDataSet(c, dataSet, index);
        drawBarImages(c, dataSet, index);
    }

We now need a method that will iterate through the DataSet and draw the star images. An appropriate method that will serve as a template is drawValues so let's copy that and change it so that is draws an image rather than text. The key to understanding this is seeing how BarBuffer works. BarBuffer holds the on-screen (pixel) co-ordinates for a bar for a given Entry at j, j + 1, j + 2, j + 3.

To clarify, j is the left x co-ordinate, j + 1 is the top y co-ordinate and so on through to the right x co-ordinate at j + 3. We'll extract these to variables to make it easier to understand:

    protected void drawBarImages(Canvas c, IBarDataSet dataSet, int index) {
        BarBuffer buffer = mBarBuffers[index];

        float left; //avoid allocation inside loop
        float right;
        float top;
        float bottom;

        for (int j = 0; j < buffer.buffer.length * mAnimator.getPhaseX(); j += 4) {
            left = buffer.buffer[j];
            right = buffer.buffer[j + 2];
            top = buffer.buffer[j + 1];
            bottom = buffer.buffer[j + 3];

            float x = (left + right) / 2f;

            if (!mViewPortHandler.isInBoundsRight(x))
                break;

            if (!mViewPortHandler.isInBoundsY(top)
                    || !mViewPortHandler.isInBoundsLeft(x))
                continue;

            BarEntry entry = dataSet.getEntryForIndex(j / 4);
            float val = entry.getY();

            if (val > 50) {
                drawStar(c, barImage, x, top);
            }
        }
    }

Here's how to consume the renderer:

    Bitmap starBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.star);
    mChart.setRenderer(new ImageBarChartRenderer(mChart, mChart.getAnimator(), mChart.getViewPortHandler(), starBitmap));

The final step to the renderer is to add logic to scale the bitmap and position it correctly. Here is the final proof-of-concept of the custom renderer:

package com.xxmassdeveloper.mpchartexample;

import android.graphics.Bitmap;
import android.graphics.Canvas;

import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.buffer.BarBuffer;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.renderer.BarChartRenderer;
import com.github.mikephil.charting.utils.ViewPortHandler;

/**
 * Created by David on 29/12/2016.
 */

public class ImageBarChartRenderer extends BarChartRenderer {

    private final Bitmap barImage;

    public ImageBarChartRenderer(BarDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler, Bitmap barImage) {
        super(chart, animator, viewPortHandler);
        this.barImage = barImage;
    }

    @Override
    public void drawData(Canvas c) {
        super.drawData(c);
    }

    @Override
    protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {
        super.drawDataSet(c, dataSet, index);
        drawBarImages(c, dataSet, index);
    }

    protected void drawBarImages(Canvas c, IBarDataSet dataSet, int index) {
        BarBuffer buffer = mBarBuffers[index];

        float left; //avoid allocation inside loop
        float right;
        float top;
        float bottom;

        final Bitmap scaledBarImage = scaleBarImage(buffer);

        int starWidth = scaledBarImage.getWidth();
        int starOffset = starWidth / 2;

        for (int j = 0; j < buffer.buffer.length * mAnimator.getPhaseX(); j += 4) {
            left = buffer.buffer[j];
            right = buffer.buffer[j + 2];
            top = buffer.buffer[j + 1];
            bottom = buffer.buffer[j + 3];

            float x = (left + right) / 2f;

            if (!mViewPortHandler.isInBoundsRight(x))
                break;

            if (!mViewPortHandler.isInBoundsY(top)
                    || !mViewPortHandler.isInBoundsLeft(x))
                continue;

            BarEntry entry = dataSet.getEntryForIndex(j / 4);
            float val = entry.getY();

            if (val > 50) {
                drawImage(c, scaledBarImage, x - starOffset, top);
            }
        }
    }

    private Bitmap scaleBarImage(BarBuffer buffer) {
        float firstLeft = buffer.buffer[0];
        float firstRight = buffer.buffer[2];
        int firstWidth = (int) Math.ceil(firstRight - firstLeft);
        return Bitmap.createScaledBitmap(barImage, firstWidth, firstWidth, false);
    }

    protected void drawImage(Canvas c, Bitmap image, float x, float y) {
        if (image != null) {
            c.drawBitmap(image, x, y, null);
        }
    }
}

Here's a screen shot - you can see that values over 50 have the star:

这篇关于MPAndroidChart:在条形图内添加自定义图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆