MPAndroidChart:在栏内添加自定义图像

San*_*iya 9 android graph mpandroidchart

我正在使用MPAndroidChart,我想在其中显示一个自定义drawable CombinedChart ,如下图所示:

条形图中的星形图像

如果条形值> =目标值,比如50,那么我想在条形图中添加一个星形图像.

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

Dav*_*son 11

要在我们的条形图中获取星形图像,我们需要创建一个自定义渲染器.因为我们的条形图使用,BarChartRenderer我们将首先对其进行子类化并为我们的图像添加参数:

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;
    }
Run Code Online (Sandbox Code Playgroud)

如果我们检查源代码,BarChartRenderer我们可以看到它调用了调用的方法drawData,然后迭代遍历每个DataSet并调用drawDataSet.drawDataSet是行动发生的地方:它正在绘制阴影和条形图.这是添加逻辑以绘制额外像图像的合适位置,所以让我们添加对方法的调用以在那里绘制图像:

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

我们现在需要一种迭代数据集并绘制星形图像的方法.一个适当的方法将作为模板,drawValues所以让我们复制并更改它,以便绘制图像而不是文本.了解这一点的关键是了解BarBuffer的工作原理.BarBuffer保持屏幕上的(像素)的坐标为在给定条目酒吧j,j + 1,j + 2,j + 3.

为了澄清,j是左x坐标,j + 1是前y坐标,依此类推到右边x坐标j + 3.我们将这些提取到变量中,以便更容易理解:

    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);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

以下是使用渲染器的方法:

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

渲染器的最后一步是添加逻辑以缩放位图并正确定位.以下是自定义渲染器的最终概念验证:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

带有自定义图像的条形图