Để có được hình ảnh ngôi sao bên trong các thanh của chúng tôi, chúng tôi sẽ cần tạo trình kết xuất tùy chỉnh. Bởi vì biểu đồ thanh của chúng tôi sử dụng BarChartRenderer
chúng tôi sẽ phân lớp này đầu tiên và thêm một tham số cho hình ảnh của chúng tôi:
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;
}
Nếu chúng ta kiểm tra nguồn cho BarChartRenderer
chúng ta có thể thấy rằng nó gọi phương thức gọi drawData
và sau đó lặp qua từng DataSet và gọi số drawDataSet
. drawDataSet
là nơi hành động đang diễn ra: nó vẽ bóng và các thanh. Đó là một nơi thích hợp để thêm logic để vẽ thêm như hình ảnh, vì vậy chúng ta hãy thêm một cuộc gọi đến một phương pháp để vẽ hình ảnh của chúng tôi có:
@Override
protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {
super.drawDataSet(c, dataSet, index);
drawBarImages(c, dataSet, index);
}
Bây giờ chúng ta cần một phương pháp mà sẽ lặp qua DataSet và vẽ ngôi sao hình ảnh. Một phương pháp thích hợp sẽ làm mẫu là drawValues
vì vậy hãy sao chép và thay đổi nó để vẽ hình ảnh thay vì văn bản. Chìa khóa để hiểu điều này là nhìn thấy cách BarBuffer hoạt động. BarBuffer giữ tọa độ trên màn hình (pixel) cho một thanh cho một Mục nhập cụ thể tại j
, j + 1
, j + 2
, j + 3
.
Để làm rõ, j
là tọa độ x bên trái, j + 1
là toạ độ y đầu và tiếp tục đến đúng x toạ độ tại j + 3
. Chúng tôi sẽ trích xuất những để biến để làm cho nó dễ dàng hơn để hiểu:
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);
}
}
}
Dưới đây là làm thế nào để tiêu thụ các renderer:
Bitmap starBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.star);
mChart.setRenderer(new ImageBarChartRenderer(mChart, mChart.getAnimator(), mChart.getViewPortHandler(), starBitmap));
Bước cuối cùng để các renderer là thêm logic để mở rộng quy mô bitmap và vị trí của nó một cách chính xác. Đây là bằng chứng-of-concept cuối cùng của các renderer tùy chỉnh:
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);
}
}
}
Dưới đây là một ảnh chụp màn hình - bạn có thể thấy rằng giá trị trên 50 có ngôi sao:
Cám ơn câu trả lời. –
Bạn được chào đón. –
Bạn đã sử dụng phiên bản biểu đồ mpandroid nào ở đây? – Amalo