[java学习]java实现柱形图、饼图的例子

更新时间:2019-11-07    来源:js教程    手机版     字体:

【www.bbyears.com--js教程】

在前面一篇博文中我们已经制作了折线图,接下来我们来制作柱形图和饼图。

柱形图的绘制流程与折线图比较类似,下面将只贴出代码,不作详细说明。

饼图相对较容易,只需计算每个数据占总比的大小旋转绘制扇形图即可,参见下述代码。

开始

柱形图

由于练手时是重写的,相对上篇博文功能可能较少,请结合上篇博文参考:

package hk.jerry.barchart;

import java.util.List;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

@SuppressLint("InlinedApi")
public class BarChartView extends View {
 private Paint paintAxis;
 private Paint paintBar;
 private Paint paintText;
 private Paint paintClear;
 private int startX;
 private int stopX;
 private int startY;
 private int stopY;
 private int chartWidth;
 private int chartHeight;
 private List dataSets;
 private float max;
 private float min;
 private int levelsX;
 private int levelsY;
 private float spaceX;
 private float spaceY;
 private int offsetLeft = 100;
 private float downX;
 private String title;
 private boolean drew = false;
 private int length = 0;
 private int maxDataSetsLength = -1;
 private boolean scrollabled = true;

 public BarChartView(Context context) {
  super(context);
 }

 public BarChartView(Context context, AttributeSet attributeSet) {
  super(context, attributeSet);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  setBackgroundColor(getResources().getColor(android.R.color.white));
  if (dataSets == null || dataSets.isEmpty()) {
   if (drew) {
    canvas.drawRect(0, 0, getWidth(), getHeight(), paintClear);
   } else {
    return;
   }
  }
  drew = true;
  init();
  //绘制X轴
  canvas.drawLine(startX, stopY, stopX, stopY, paintAxis);
  //绘制刻度与数据坐标,只画在视域内的11个+左右缓冲2个柱形
  int j = (int) Math.ceil(0 - offsetLeft / spaceX) - 1;
  for (int i = 0; i <= (levelsX > 11 ? 11 : levelsX) + 1; i++, j++) {
   if (j < 0 || j >= dataSets.size()) { //防止数组下标越界
    continue;
   }
   DataSet dataSet = dataSets.get(j);
   float x = getPositionX(j);
   paintAxis.setTextAlign(Align.CENTER);
   canvas.drawLine(x, stopY, x, stopY + 10, paintAxis);
   canvas.drawText(dataSet.name, x, stopY + 25, paintAxis);
   float y = getPositionY(dataSet.value);
   canvas.drawRect(x - 20, y, x + 20, stopY, paintBar);
   canvas.drawText(String.valueOf(dataSet.value), x, y - 10, paintBar);
  }
  canvas.drawRect(0, 0, startX, getHeight(), paintClear);
  canvas.drawLine(startX, startY, startX, stopY, paintAxis);
  for (int i = 0; i < levelsY; i++) {
   float y = getPositionY(min + i * 5);
   paintAxis.setTextAlign(Align.RIGHT);
   canvas.drawLine(startX - 10, y, startX, y, paintAxis);
   canvas.drawText(String.valueOf((int) min + i * 5), startX - 12, y + 5, paintAxis);
  }

  if (title != null) {
   Log.d("test", title);
   canvas.drawText(title, getWidth() / 2, 0 + 50, paintText);
  }
 }

 private void init() {
  paintAxis = new Paint();
  paintAxis.setStrokeWidth(3);
  paintAxis.setAntiAlias(true);
  paintAxis.setTextSize(16);
  paintAxis.setColor(getResources().getColor(android.R.color.secondary_text_dark));

  paintBar = new Paint();
  paintBar.setStrokeWidth(3);
  paintBar.setAntiAlias(true);
  paintBar.setTextSize(20);
  paintBar.setColor(getResources().getColor(android.R.color.holo_green_dark));
  paintBar.setTextAlign(Align.CENTER);

  paintText = new Paint();
  paintText.setAntiAlias(true);
  paintText.setTextSize(35);
  paintText.setTextAlign(Align.CENTER);
  paintText.setColor(getResources().getColor(android.R.color.holo_green_dark));

  paintClear = new Paint();
  paintClear.setColor(getResources().getColor(android.R.color.white));

  startX = 50;
  stopX = getWidth();
  startY = 80;
  stopY = getHeight() - 50;
  chartHeight = stopY - startY;
  chartWidth = stopX - startX;

  max = min = dataSets.get(0).value;
  for (int i = 0; i < dataSets.size(); i++) {    DataSet dataSet = dataSets.get(i);    if (dataSet.value > max) {
    max = dataSet.value;
   }
   if (dataSet.value < min) {     min = dataSet.value;    }   }   levelsX = dataSets.size() + 1;   levelsY = (int) Math.ceil((max - min) / 5) + 1;   spaceY = chartHeight / levelsY;   spaceX = levelsX > 10 ? chartWidth / 11 : chartWidth / (levelsX + 1);

  length = (int) (dataSets.size() * spaceX);
 }

 private float getPositionX(int X) {
  return spaceX * X + offsetLeft;
 }

 private float getPositionY(float value) {
  int exceedNum = (int) Math.floor((value - min) / 5) + 1;
  return ((float) stopY) - spaceY * exceedNum - ((value - min) % 5 / 5) * spaceY;
 }

 public void empty() {
  dataSets = null;
  title = null;
  length = 0;
  invalidate();
 }

 public void setDataSets(List dataSets) {
  length = 0;
  this.dataSets = dataSets;
  invalidate();
 }

 /*
  * 添加数据集
  */
 public void addDataSet(DataSet dataSet) {
  if (maxDataSetsLength != -1 && dataSets.size() > maxDataSetsLength) {
   dataSets.remove(0);
  }
  dataSets.add(dataSet);
  scrollToEnd();
 }

 public void setMaxDataSetsLength(int maxDataSetsLength) {
  this.maxDataSetsLength = maxDataSetsLength;
 }

 public void setScrollable(boolean scrollabled) {
  this.scrollabled = scrollabled;
 }

 public void setTitle(String title) {
  this.title = title;
  invalidate();
 }

 public void scrollToStart() {
  if (!drew) {
   invalidate();
  }
  offsetLeft = 100;
  invalidate();
 }

 public void scrollToEnd() {
  if (!drew) {
   invalidate();
  }
  offsetLeft = chartWidth >= length ? 100 : (0 - (length - chartWidth) - 100);
  invalidate();
 }

 public boolean isScrolledToStart() {
  return offsetLeft >= 100;
 }

 public boolean isScrolledToEnd() {
  return chartWidth >= length ? (offsetLeft <= 100) : (offsetLeft < 0 - (length - chartWidth));
 }

 @SuppressLint("ClickableViewAccessibility")
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   downX = event.getRawX();
   break;
  case MotionEvent.ACTION_MOVE:
   if (!scrollabled) {
    return true;
   }
   offsetLeft += event.getRawX() - downX;
   downX = event.getRawX();
   if (isScrolledToStart()) {
    scrollToStart();
   } else if (isScrolledToEnd()) {
    scrollToEnd();
   } else {
    invalidate();
   }
   break;
  }
  return true;
 }

 public static class DataSet {
  public String name;
  public float value;

  public DataSet(String name, float value) {
   this.name = name;
   this.value = value;
  }
 }
}

测试代码是一样的,所以我在此就不贴出来了。

饼图

控件代码:

package hk.jerry.piechart;

import java.util.List;
import java.util.Random;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

@SuppressLint({ "NewApi", "DrawAllocation" })
public class PieChartView extends View {
 private Paint paintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); //饼图轮廓画刷
 private Paint paintPie = new Paint(Paint.ANTI_ALIAS_FLAG); //饼图扇形画刷
 private Paint paintText = new Paint(Paint.ANTI_ALIAS_FLAG); //饼图文字画刷
 private float startX, stopX, startY, stopY; //饼图开始、结束位置
 private float cx, cy, radius; //圆心X、Y点,半径
 private float sum; //数据总和
 private List dataSets; //数据集
 private Random random = new Random(); //随机类
 private String title; //标题

 public PieChartView(Context context) {
  super(context);
 }

 public PieChartView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

 public void init() {
  //设置饼图轮廓画刷参数
  BlurMaskFilter filter = new BlurMaskFilter(1, BlurMaskFilter.Blur.INNER);
  paintStroke.setARGB(255, 155, 155, 155);
  paintStroke.setStrokeWidth(4);
  paintStroke.setStyle(Paint.Style.STROKE);
  paintStroke.setMaskFilter(filter);
  //设置饼图扇形画刷参数
  paintPie.setStyle(Paint.Style.FILL);
  paintPie.setMaskFilter(filter);
  paintPie.setTextSize(25);
  //设置饼图文字画刷参数
  paintText.setTextSize(35);
  //计算饼图开始与结束位置,为确保饼图为正圆,左右与上下宽度要一致
  startX = 10;
  startY = 100;
  stopX = stopY = (getHeight() < getWidth() ? getHeight() : getWidth()) - 50;
  //根据开始与结束位置计算圆心坐标
  cx = (stopX - startX) / 2 + startX;
  cy = (stopY - startY) / 2 + startY;
  //计算半径
  radius = (stopX - startX) / 2;
  //遍历数据集计算总和
  sum = 0;
  for (int i = 0; i < dataSets.size(); i++) {
   sum += dataSets.get(i).value;
  }
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  init();
  //生成Path,并绘制饼图的轮廓
  Path path = new Path();
  path.addCircle(cx, cy, radius, Direction.CW);
  canvas.drawPath(path, paintStroke);
  //生成RectF,用于后续的扇形绘制
  RectF rectF = new RectF(cx - radius, cy - radius, cx + radius, cy + radius);
  //扇形偏移角度
  float startAngle = 0;
  //饼图数据标志偏移值
  float offset = 30;
  for (int i = 0; i < dataSets.size(); i++) {
   DataSet dataSet = dataSets.get(i);
   float percentage = dataSet.value / sum * 360; //计算百分比得出角度
   paintPie.setARGB(255, random.nextInt(255), random.nextInt(255), random.nextInt(255)); //随机生成颜色
   canvas.drawArc(rectF, startAngle, percentage, true, paintPie); //绘制扇形
   startAngle += percentage; //将刚才计算到的角度与偏移角度相加,作为下一个扇形的偏移角度,便于绘制
   canvas.drawRect(stopX + 60, startY + offset, stopX + 100, startY + offset + 30, paintPie); //绘制数据标志图
   canvas.drawText(dataSet.name + "(" + (dataSet.value / sum * 100) + "%)", stopX + 130, startY + offset + 23, paintPie); //绘制数据值
   offset += 50;
  }
  if (title != null) { //绘制标题
   canvas.drawText(title, getWidth() / 2, 50, paintText);
  }
 }

 public void setTitle(String title) {
  this.title = title;
 }

 public void setDataSets(List dataSets) {
  this.dataSets = dataSets;
  invalidate();
 }

 public void addDataSet(DataSet dataSet) {
  dataSets.add(dataSet);
  invalidate();
 }

 public static class DataSet {
  public String name;
  public float value;

  public DataSet(String name, float value) {
   this.name = name;
   this.value = value;
  }
 }

}

布局代码我也不上了,跟上篇博文类似,直接上测试代码:

final PieChartView pc = (PieChartView) findViewById(R.id.pc_test);
pc.setTitle("测试图表");
Random random = new Random();
List dataSets = new ArrayList();
for (int i = 0; i <= 5; i++) {
    float value = random.nextInt(50);
    dataSets.add(new DataSet("第" + (i + 1) + "个数据", value));
}
pc.setDataSets(dataSets);
btnAdd.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
  pc.addDataSet(new DataSet(etName.getText().toString(), Float.valueOf(etValue.getText().toString())));
 }
});

运行效果

本文来源:http://www.bbyears.com/wangyezhizuo/77778.html

热门标签

更多>>

本类排行