如何使用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);
}
}