如何使用MPAndroidChart在折线图的最后一点放置图像?

如何使用MPAndroidChart在折线图的最后一点放置图像?,android,mpandroidchart,Android,Mpandroidchart,我在库中使用下面的代码,但它在所有点上都放置了图像。我只希望图像位于最后一点 public class ImageLineChartRenderer extends LineChartRenderer { private final LineChart lineChart; private final Bitmap image; ImageLineChartRenderer(LineChart chart, ChartAnimator animator, ViewPor

我在库中使用下面的代码,但它在所有点上都放置了图像。我只希望图像位于最后一点

public class ImageLineChartRenderer extends LineChartRenderer {
    private final LineChart lineChart;
    private final Bitmap image;

    ImageLineChartRenderer(LineChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler, Bitmap image) {
        super(chart, animator, viewPortHandler);
        this.lineChart = chart;
        this.image = image;
    }

    private float[] mCirclesBuffer = new float[2];

    @Override
    protected void drawCircles(Canvas c) {
        mRenderPaint.setStyle(Paint.Style.FILL);
        float phaseY = mAnimator.getPhaseY();
        mCirclesBuffer[0] = 0;
        mCirclesBuffer[1] = 0;
        List<ILineDataSet> dataSets = mChart.getLineData().getDataSets();

        //Draw bitmap image for every data set with size as radius * 10, and store it in scaled bitmaps array
        Bitmap[] scaledBitmaps = new Bitmap[dataSets.size()];
        float[] scaledBitmapOffsets = new float[dataSets.size()];
        for (int i = 0; i < dataSets.size(); i++) {
            float imageSize = dataSets.get(i).getCircleRadius() * 10;
            scaledBitmapOffsets[i] = imageSize / 2f;
            scaledBitmaps[i] = scaleImage((int) imageSize);
        }

        for (int i = 0; i < dataSets.size(); i++) {
            ILineDataSet dataSet = dataSets.get(i);

            if (!dataSet.isVisible() || !dataSet.isDrawCirclesEnabled() || dataSet.getEntryCount() == 0)
                continue;

            mCirclePaintInner.setColor(dataSet.getCircleHoleColor());
            Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
            mXBounds.set(mChart, dataSet);


            int boundsRangeCount = mXBounds.range + mXBounds.min;
            for (int j = mXBounds.min; j <= boundsRangeCount; j++) {
                Entry e = dataSet.getEntryForIndex(j);
                if (e == null) break;
                mCirclesBuffer[0] = e.getX();
                mCirclesBuffer[1] = e.getY() * phaseY;
                trans.pointValuesToPixel(mCirclesBuffer);
                if (!mViewPortHandler.isInBoundsRight(mCirclesBuffer[0]))
                    break;
                if (!mViewPortHandler.isInBoundsLeft(mCirclesBuffer[0]) || !mViewPortHandler.isInBoundsY(mCirclesBuffer[1]))
                    continue;

                if (scaledBitmaps[i] != null) {
                    c.drawBitmap(scaledBitmaps[i],
                            mCirclesBuffer[0] - scaledBitmapOffsets[i],
                            mCirclesBuffer[1] - scaledBitmapOffsets[i],
                            mRenderPaint);
                }
            }
        }

    }



    private Bitmap scaleImage(int radius) {
        return Bitmap.createScaledBitmap(image, radius, radius, false);
    }
}


尝试更改这段代码:

for (int j = mXBounds.min; j <= boundsRangeCount; j++)
for(int j=mXBounds.min;j多亏了,我将我的代码重写如下,并且工作正常:

public class ImageLineChartRenderer extends LineChartRenderer {
    private final LineChart lineChart;
    private final Bitmap image;


    ImageLineChartRenderer(LineChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler, Bitmap image) {
        super(chart, animator, viewPortHandler);
        this.lineChart = chart;
        this.image = image;
    }

    private float[] mCirclesBuffer = new float[2];
    private float[] imageBuffer = new float[2];

    @Override
    protected void drawCircles(Canvas c) {
        mRenderPaint.setStyle(Paint.Style.FILL);
        float phaseY = mAnimator.getPhaseY();
        mCirclesBuffer[0] = 0;
        mCirclesBuffer[1] = 0;
        imageBuffer[0] = 0;
        imageBuffer[1] = 0;
        List<ILineDataSet> dataSets = mChart.getLineData().getDataSets();

        //Draw bitmap image for every data set with size as radius * 10, and store it in scaled bitmaps array
        Bitmap[] scaledBitmaps = new Bitmap[dataSets.size()];
        float[] scaledBitmapOffsets = new float[dataSets.size()];
        for (int i = dataSets.size() - 1; i < dataSets.size(); i++) {
            float imageSize = dataSets.get(i).getCircleRadius() * 2;
            scaledBitmapOffsets[i] = imageSize / 2f;
            scaledBitmaps[i] = scaleImage((int) imageSize);
        }

        for (int i = 0; i < dataSets.size(); i++) {
            ILineDataSet dataSet = dataSets.get(i);

            if (!dataSet.isVisible() || !dataSet.isDrawCirclesEnabled() || dataSet.getEntryCount() == 0)
                continue;

            mCirclePaintInner.setColor(dataSet.getCircleHoleColor());
            Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
            mXBounds.set(mChart, dataSet);

            int boundsRangeCount = mXBounds.range + mXBounds.min;

            float circleRadius = dataSet.getCircleRadius();
            float circleHoleRadius = dataSet.getCircleHoleRadius();
            boolean drawCircleHole = dataSet.isDrawCircleHoleEnabled() &&
                    circleHoleRadius < circleRadius &&
                    circleHoleRadius > 0.f;
            boolean drawTransparentCircleHole = drawCircleHole &&
                    dataSet.getCircleHoleColor() == ColorTemplate.COLOR_NONE;

            DataSetImageCache imageCache;

            if (mImageCaches.containsKey(dataSet)) {
                imageCache = mImageCaches.get(dataSet);
            } else {
                imageCache = new DataSetImageCache();
                mImageCaches.put(dataSet, imageCache);
            }

            boolean changeRequired = imageCache.init(dataSet);

            // only fill the cache with new bitmaps if a change is required
            if (changeRequired) {
                imageCache.fill(dataSet, drawCircleHole, drawTransparentCircleHole);
            }

            for (int j = mXBounds.min; j <= boundsRangeCount; j++) {

                Entry e = dataSet.getEntryForIndex(j);

                if (e == null) break;

                mCirclesBuffer[0] = e.getX();
                mCirclesBuffer[1] = e.getY() * phaseY;

                trans.pointValuesToPixel(mCirclesBuffer);

                if (!mViewPortHandler.isInBoundsRight(mCirclesBuffer[0]))
                    break;

                if (!mViewPortHandler.isInBoundsLeft(mCirclesBuffer[0]) ||
                        !mViewPortHandler.isInBoundsY(mCirclesBuffer[1]))
                    continue;

                Bitmap circleBitmap = imageCache.getBitmap(j);

                if (circleBitmap != null) {
                    c.drawBitmap(circleBitmap, mCirclesBuffer[0] - circleRadius, mCirclesBuffer[1] - circleRadius, null);
                }
            }
            if (boundsRangeCount == dataSet.getEntryCount() - 1) {
                for (int j = boundsRangeCount; j <= boundsRangeCount; j++) {
                    Entry e = dataSet.getEntryForIndex(j);
                    if (e == null) break;
                    imageBuffer[0] = e.getX();
                    imageBuffer[1] = e.getY() * phaseY;
                    trans.pointValuesToPixel(imageBuffer);
                    if (!mViewPortHandler.isInBoundsRight(imageBuffer[0]))
                        break;
                    if (!mViewPortHandler.isInBoundsLeft(imageBuffer[0]) || !mViewPortHandler.isInBoundsY(imageBuffer[1]))
                        continue;

                    if (scaledBitmaps[i] != null) {
                        c.drawBitmap(scaledBitmaps[i],
                                imageBuffer[0] - scaledBitmapOffsets[i],
                                imageBuffer[1] - scaledBitmapOffsets[i],
                                mRenderPaint);
                    }
                }
            }



        }

    }


    private HashMap<IDataSet, ImageLineChartRenderer.DataSetImageCache> mImageCaches = new HashMap<>();

    private class DataSetImageCache {

        private Path mCirclePathBuffer = new Path();

        private Bitmap[] circleBitmaps;

        /**
         * Sets up the cache, returns true if a change of cache was required.
         *
         * @param set
         * @return
         */
        protected boolean init(ILineDataSet set) {

            int size = set.getCircleColorCount();
            boolean changeRequired = false;

            if (circleBitmaps == null) {
                circleBitmaps = new Bitmap[size];
                changeRequired = true;
            } else if (circleBitmaps.length != size) {
                circleBitmaps = new Bitmap[size];
                changeRequired = true;
            }

            return changeRequired;
        }

        /**
         * Fills the cache with bitmaps for the given dataset.
         *
         * @param set
         * @param drawCircleHole
         * @param drawTransparentCircleHole
         */
        protected void fill(ILineDataSet set, boolean drawCircleHole, boolean drawTransparentCircleHole) {

            int colorCount = set.getCircleColorCount();
            float circleRadius = set.getCircleRadius();
            float circleHoleRadius = set.getCircleHoleRadius();

            for (int i = 0; i < colorCount; i++) {

                Bitmap.Config conf = Bitmap.Config.ARGB_4444;
                Bitmap circleBitmap = Bitmap.createBitmap((int) (circleRadius * 2.1), (int) (circleRadius * 2.1), conf);

                Canvas canvas = new Canvas(circleBitmap);
                circleBitmaps[i] = circleBitmap;
                mRenderPaint.setColor(set.getCircleColor(i));

                if (drawTransparentCircleHole) {
                    // Begin path for circle with hole
                    mCirclePathBuffer.reset();

                    mCirclePathBuffer.addCircle(
                            circleRadius,
                            circleRadius,
                            circleRadius,
                            Path.Direction.CW);

                    // Cut hole in path
                    mCirclePathBuffer.addCircle(
                            circleRadius,
                            circleRadius,
                            circleHoleRadius,
                            Path.Direction.CCW);

                    // Fill in-between
                    canvas.drawPath(mCirclePathBuffer, mRenderPaint);
                } else {

                    canvas.drawCircle(
                            circleRadius,
                            circleRadius,
                            circleRadius,
                            mRenderPaint);

                    if (drawCircleHole) {
                        canvas.drawCircle(
                                circleRadius,
                                circleRadius,
                                circleHoleRadius,
                                mCirclePaintInner);
                    }
                }
            }
        }

        /**
         * Returns the cached Bitmap at the given index.
         *
         * @param index
         * @return
         */
        protected Bitmap getBitmap(int index) {
            return circleBitmaps[index % circleBitmaps.length];
        }
    }


    private Bitmap scaleImage(int radius) {
        return Bitmap.createScaledBitmap(image, radius, radius, false);
    }
}
公共类ImageLineChartRenderer扩展了LineChartRenderer{
私人最终线形图线形图;
私有最终位图图像;
ImageLineChartRenderer(线条图、图表动画师动画师、ViewPortHandler ViewPortHandler、位图图像){
超级(图表、动画师、viewPortHandler);
这个。折线图=图表;
这个图像=图像;
}
私有浮点[]mCirclesBuffer=新浮点[2];
私有浮点[]imageBuffer=新浮点[2];
@凌驾
受保护的空心画圈(画布c){
mRenderPaint.setStyle(油漆、样式、填充);
float phaseY=mAnimator.getPhaseY();
mCirclesBuffer[0]=0;
mCirclesBuffer[1]=0;
imageBuffer[0]=0;
imageBuffer[1]=0;
列表数据集=mChart.getLineData().getDataSets();
//为大小为radius*10的每个数据集绘制位图图像,并将其存储在缩放位图数组中
位图[]缩放位图=新位图[dataset.size()];
float[]scaledBitmapOffsets=新的float[dataset.size()];
对于(int i=dataSets.size()-1;i0.f;
布尔drawTransparentCircleHole=drawCircleHole&&
dataSet.getCircleHoleColor()==ColorTemplate.COLOR\u无;
DataSetImageCache-imageCache;
if(mImageCaches.containsKey(数据集)){
imageCache=mImageCaches.get(数据集);
}否则{
imageCache=新的DataSetImageCache();
mImageCaches.put(数据集,图像缓存);
}
boolean changeRequired=imageCache.init(数据集);
//仅当需要更改时,才使用新位图填充缓存
如果(需要更改){
fill(数据集、drawCircleHole、drawTransparentCircleHole);
}

对于(int j=mXBounds.min;j)您希望仅在7月12日有圆吗?我希望图像位于最后一个圆的位置。这里有5个圆。我希望图像仅位于最后一个圆的位置(7月3日至12日)。感谢您将图像放在末尾,但删除了其他圆。Thanks@user2553586我相信这就是你想要的,对吗?
for (int j = boundsRangeCount; j <= boundsRangeCount; j++)
public class ImageLineChartRenderer extends LineChartRenderer {
    private final LineChart lineChart;
    private final Bitmap image;


    ImageLineChartRenderer(LineChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler, Bitmap image) {
        super(chart, animator, viewPortHandler);
        this.lineChart = chart;
        this.image = image;
    }

    private float[] mCirclesBuffer = new float[2];
    private float[] imageBuffer = new float[2];

    @Override
    protected void drawCircles(Canvas c) {
        mRenderPaint.setStyle(Paint.Style.FILL);
        float phaseY = mAnimator.getPhaseY();
        mCirclesBuffer[0] = 0;
        mCirclesBuffer[1] = 0;
        imageBuffer[0] = 0;
        imageBuffer[1] = 0;
        List<ILineDataSet> dataSets = mChart.getLineData().getDataSets();

        //Draw bitmap image for every data set with size as radius * 10, and store it in scaled bitmaps array
        Bitmap[] scaledBitmaps = new Bitmap[dataSets.size()];
        float[] scaledBitmapOffsets = new float[dataSets.size()];
        for (int i = dataSets.size() - 1; i < dataSets.size(); i++) {
            float imageSize = dataSets.get(i).getCircleRadius() * 2;
            scaledBitmapOffsets[i] = imageSize / 2f;
            scaledBitmaps[i] = scaleImage((int) imageSize);
        }

        for (int i = 0; i < dataSets.size(); i++) {
            ILineDataSet dataSet = dataSets.get(i);

            if (!dataSet.isVisible() || !dataSet.isDrawCirclesEnabled() || dataSet.getEntryCount() == 0)
                continue;

            mCirclePaintInner.setColor(dataSet.getCircleHoleColor());
            Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
            mXBounds.set(mChart, dataSet);

            int boundsRangeCount = mXBounds.range + mXBounds.min;

            float circleRadius = dataSet.getCircleRadius();
            float circleHoleRadius = dataSet.getCircleHoleRadius();
            boolean drawCircleHole = dataSet.isDrawCircleHoleEnabled() &&
                    circleHoleRadius < circleRadius &&
                    circleHoleRadius > 0.f;
            boolean drawTransparentCircleHole = drawCircleHole &&
                    dataSet.getCircleHoleColor() == ColorTemplate.COLOR_NONE;

            DataSetImageCache imageCache;

            if (mImageCaches.containsKey(dataSet)) {
                imageCache = mImageCaches.get(dataSet);
            } else {
                imageCache = new DataSetImageCache();
                mImageCaches.put(dataSet, imageCache);
            }

            boolean changeRequired = imageCache.init(dataSet);

            // only fill the cache with new bitmaps if a change is required
            if (changeRequired) {
                imageCache.fill(dataSet, drawCircleHole, drawTransparentCircleHole);
            }

            for (int j = mXBounds.min; j <= boundsRangeCount; j++) {

                Entry e = dataSet.getEntryForIndex(j);

                if (e == null) break;

                mCirclesBuffer[0] = e.getX();
                mCirclesBuffer[1] = e.getY() * phaseY;

                trans.pointValuesToPixel(mCirclesBuffer);

                if (!mViewPortHandler.isInBoundsRight(mCirclesBuffer[0]))
                    break;

                if (!mViewPortHandler.isInBoundsLeft(mCirclesBuffer[0]) ||
                        !mViewPortHandler.isInBoundsY(mCirclesBuffer[1]))
                    continue;

                Bitmap circleBitmap = imageCache.getBitmap(j);

                if (circleBitmap != null) {
                    c.drawBitmap(circleBitmap, mCirclesBuffer[0] - circleRadius, mCirclesBuffer[1] - circleRadius, null);
                }
            }
            if (boundsRangeCount == dataSet.getEntryCount() - 1) {
                for (int j = boundsRangeCount; j <= boundsRangeCount; j++) {
                    Entry e = dataSet.getEntryForIndex(j);
                    if (e == null) break;
                    imageBuffer[0] = e.getX();
                    imageBuffer[1] = e.getY() * phaseY;
                    trans.pointValuesToPixel(imageBuffer);
                    if (!mViewPortHandler.isInBoundsRight(imageBuffer[0]))
                        break;
                    if (!mViewPortHandler.isInBoundsLeft(imageBuffer[0]) || !mViewPortHandler.isInBoundsY(imageBuffer[1]))
                        continue;

                    if (scaledBitmaps[i] != null) {
                        c.drawBitmap(scaledBitmaps[i],
                                imageBuffer[0] - scaledBitmapOffsets[i],
                                imageBuffer[1] - scaledBitmapOffsets[i],
                                mRenderPaint);
                    }
                }
            }



        }

    }


    private HashMap<IDataSet, ImageLineChartRenderer.DataSetImageCache> mImageCaches = new HashMap<>();

    private class DataSetImageCache {

        private Path mCirclePathBuffer = new Path();

        private Bitmap[] circleBitmaps;

        /**
         * Sets up the cache, returns true if a change of cache was required.
         *
         * @param set
         * @return
         */
        protected boolean init(ILineDataSet set) {

            int size = set.getCircleColorCount();
            boolean changeRequired = false;

            if (circleBitmaps == null) {
                circleBitmaps = new Bitmap[size];
                changeRequired = true;
            } else if (circleBitmaps.length != size) {
                circleBitmaps = new Bitmap[size];
                changeRequired = true;
            }

            return changeRequired;
        }

        /**
         * Fills the cache with bitmaps for the given dataset.
         *
         * @param set
         * @param drawCircleHole
         * @param drawTransparentCircleHole
         */
        protected void fill(ILineDataSet set, boolean drawCircleHole, boolean drawTransparentCircleHole) {

            int colorCount = set.getCircleColorCount();
            float circleRadius = set.getCircleRadius();
            float circleHoleRadius = set.getCircleHoleRadius();

            for (int i = 0; i < colorCount; i++) {

                Bitmap.Config conf = Bitmap.Config.ARGB_4444;
                Bitmap circleBitmap = Bitmap.createBitmap((int) (circleRadius * 2.1), (int) (circleRadius * 2.1), conf);

                Canvas canvas = new Canvas(circleBitmap);
                circleBitmaps[i] = circleBitmap;
                mRenderPaint.setColor(set.getCircleColor(i));

                if (drawTransparentCircleHole) {
                    // Begin path for circle with hole
                    mCirclePathBuffer.reset();

                    mCirclePathBuffer.addCircle(
                            circleRadius,
                            circleRadius,
                            circleRadius,
                            Path.Direction.CW);

                    // Cut hole in path
                    mCirclePathBuffer.addCircle(
                            circleRadius,
                            circleRadius,
                            circleHoleRadius,
                            Path.Direction.CCW);

                    // Fill in-between
                    canvas.drawPath(mCirclePathBuffer, mRenderPaint);
                } else {

                    canvas.drawCircle(
                            circleRadius,
                            circleRadius,
                            circleRadius,
                            mRenderPaint);

                    if (drawCircleHole) {
                        canvas.drawCircle(
                                circleRadius,
                                circleRadius,
                                circleHoleRadius,
                                mCirclePaintInner);
                    }
                }
            }
        }

        /**
         * Returns the cached Bitmap at the given index.
         *
         * @param index
         * @return
         */
        protected Bitmap getBitmap(int index) {
            return circleBitmaps[index % circleBitmaps.length];
        }
    }


    private Bitmap scaleImage(int radius) {
        return Bitmap.createScaledBitmap(image, radius, radius, false);
    }
}