2016-12-27 20 views

Trả lời

4

Để 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:

bar chart with custom image inside bars

+0

Cám ơn câu trả lời. –

+0

Bạn được chào đón. –

+0

Bạn đã sử dụng phiên bản biểu đồ mpandroid nào ở đây? – Amalo

Các vấn đề liên quan