主要用于Canvas一个特别简单的小demo。

能够手动点击看每一个月份的数据。很easy。就是用paint在canvas上画出来的。

主要内容就是计算左边价格的位置,以下日期的位置,三根虚线的位置,五个点四根折线加价格标签的位置。

绿色价格标签是由一个圆角矩形一个三角形加一个text组成的。能够依据点击的位置在五个点上面显示。

两种方式:一种加动画一种不带动画。带动画的就是先显示五个点,然后折线从左往右显示

动画的实现是用handler不断改变须要画的折线的坐标的位置,然后一路画过去。

代码例如以下。须要的能够去github自行下载。

喜欢的请star

public class ChartView extends ImageView {

    /**
* 须要传入一个ChartBeanList,里面包括表格上显示的每一个点的信息。包括时间点和价格
*
*/ public static int height = 300;
public static double width = 600; private int heightReal;// 图表实际的高度
private int heightText = 70;// 底部显示时间的区域
private int heightTop = 0;// 图表上面的空白区 private int multi = 1;// 用来适配各种分辨率的机器的,为倍数
private int radi = 5 * multi;// 圆点的半径 private int widthReal;// 图表实际的宽度
private int widthText = 50 * multi;// 图表左边显示价格的区域
private int widthHead = 50;// 价格区域右边,图表左边的空白区
private int widthFoot = 25 * multi;
private int miles = 5;// 增长的毫秒数
private int px = 10;// 每毫秒添加的像素数
private boolean hasAnim = false; private double x1 = 0;
private double x2 = 0;
private double x3 = 0;
private double x4 = 0;
private double x5 = 0; private PointF p1 = new PointF();
private PointF p2 = new PointF();
private PointF p3 = new PointF();
private PointF p4 = new PointF();
private PointF p5 = new PointF();
private float p2x;
private float p3x;
private float p4x;
private float p5x;
private float p2y;
private float p3y;
private float p4y;
private float p5y;
boolean p2Init = true;
boolean isFirstRun = true;
boolean x1Complete = true;
boolean x2Complete = false;
boolean x3Complete = false;
boolean x4Complete = false;
boolean x5Complete = false;
private double min = 0d;
private double max = 100000d;
private PointF pic;
private List<ChartBean> mChartBeanList = new ArrayList<ChartBean>();
private double price;
private String unit = "元/斤";
private MyHandler handler;
private Paint p;
private float left;
private float top;
private float right;
private float bottom;
private int textWidth; public ChartView(Context context) {
super(context);
init();
} public ChartView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
} public ChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} private void init() {
handler = new MyHandler(); } public void setData(List<ChartBean> list, String unit, boolean hasAnim) {
this.mChartBeanList = list;
this.hasAnim = hasAnim;
if ("".equals(unit)) {
this.unit = unit;
}
// 4,6,2,3,5
try {
x1 = list.get(0).getPrice();
x2 = list.get(1).getPrice();
x3 = list.get(2).getPrice();
x4 = list.get(3).getPrice();
x5 = list.get(4).getPrice();
} catch (Exception e) {
e.printStackTrace();
}
max = list.get(0).getPrice();
for (int i = 0; i < list.size(); i++) {
if (max < list.get(i).getPrice()) {
max = list.get(i).getPrice();
}
}
} public void setMaxMin(double max, double min) {
} @SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) { super.onDraw(canvas);
p = new Paint();
p.setAntiAlias(true);
p.setColor(Color.GRAY);
p.setTypeface(Typeface.DEFAULT);
Path path = new Path(); width = canvas.getWidth();
height = canvas.getHeight();
multi = (int) Math.ceil(width / 560);
int width = canvas.getWidth();
widthText = 50 * multi;// 图表左边显示价格的区域
widthFoot = 25 * multi;
radi = 5 * multi; heightTop = 0;
heightReal = height - heightText - heightTop;
heightTop = heightReal / 4;
heightReal = height - heightText - heightTop;
widthReal = ((int) width - widthText - widthHead - widthFoot); /** 画左边的价格文字 */
p.setTextSize(17 * multi);
canvas.drawText(String.format("%.2f", (min + (max - min))), widthText - 35 * multi, heightTop, p);
canvas.drawText(String.format("%.2f", (min + (max - min) * 2 / 3)), widthText - 35 * multi, heightTop
+ heightReal / 3, p);
canvas.drawText(String.format("%.2f", (min + (max - min) / 3)), widthText - 35 * multi, heightTop + heightReal
* 2 / 3, p);
canvas.drawText(unit, widthText - 35 * multi - 5, heightTop + heightReal + 5, p);
/** 画底下的日期文字 */
try {
switch (mChartBeanList.size()) {
case 5:
canvas.drawText(mChartBeanList.get(4).getDate() + "", widthText + widthReal, 50 + heightTop
+ heightReal, p);
case 4:
canvas.drawText(mChartBeanList.get(3).getDate() + "", widthText + widthReal * 3 / 4, 50 + heightTop
+ heightReal, p);
case 3:
canvas.drawText(mChartBeanList.get(2).getDate() + "", widthText + widthReal / 2, 50 + heightTop
+ heightReal, p);
case 2:
canvas.drawText(mChartBeanList.get(1).getDate() + "", widthText + widthReal / 4, 50 + heightTop
+ heightReal, p);
case 1:
canvas.drawText(mChartBeanList.get(0).getDate() + "", widthText, 50 + heightTop + heightReal, p);
case 0:
break;
}
} catch (Exception e) {
e.printStackTrace();
} p1.x = widthText + widthHead;
p1.y = (float) (heightTop + getHeight(x1));
p2.x = widthText + widthHead + widthReal / 4;
p2.y = (float) (heightTop + getHeight(x2));
p3.x = widthText + widthHead + widthReal / 2;
p3.y = (float) (heightTop + getHeight(x3));
p4.x = widthText + widthHead + widthReal * 3 / 4;
p4.y = (float) (heightTop + getHeight(x4));
p5.x = widthText + widthHead + widthReal;
p5.y = (float) (heightTop + getHeight(x5));
if (p2Init) {
/** 初始化pp2 */
p2x = p1.x;
p2y = p1.y;
p2Init = false;
} /** 最底下的粗线 */
p.setColor(Color.GRAY);
p.setStrokeWidth(2);
canvas.drawLine(widthText, heightTop + heightReal, (float) width, heightTop + heightReal, p); /** 画三根虚线 */
p.setColor(Color.GRAY);
p.setStrokeWidth(1);
p.setStyle(Paint.Style.STROKE);
PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
p.setPathEffect(effects);
path.moveTo(widthText, heightTop + heightReal * 2 / 3);
path.lineTo(width, heightTop + heightReal * 2 / 3);
canvas.drawPath(path, p);
path.moveTo(widthText, heightTop + heightReal / 3);
path.lineTo(width, heightTop + heightReal / 3);
canvas.drawPath(path, p);
path.moveTo(widthText, heightTop);
path.lineTo(width, heightTop);
canvas.drawPath(path, p);
p.setStyle(Paint.Style.FILL);
p.setColor(getResources().getColor(R.color.green_chart));
p.setStrokeWidth(3 * multi);
/** 几个点连起来的折线 */
try {
switch (mChartBeanList.size()) {
case 0:
break;
case 1:
canvas.drawCircle(p1.x, p1.y, radi, p);
if (pic == null) {
pic = new PointF();
pic = p1;
price = x1;
}
break;
case 2:
drawLine(canvas, p);
canvas.drawCircle(p1.x, p1.y, radi, p);
canvas.drawCircle(p2.x, p2.y, radi, p);
if (pic == null) {
pic = new PointF();
pic = p2;
price = x2;
}
break;
case 3:
drawLine(canvas, p);
canvas.drawCircle(p1.x, p1.y, radi, p);
canvas.drawCircle(p2.x, p2.y, radi, p);
canvas.drawCircle(p3.x, p3.y, radi, p);
if (pic == null) {
pic = new PointF();
pic = p3;
price = x3;
}
break;
case 4:
drawLine(canvas, p);
canvas.drawCircle(p1.x, p1.y, radi, p);
canvas.drawCircle(p2.x, p2.y, radi, p);
canvas.drawCircle(p3.x, p3.y, radi, p);
canvas.drawCircle(p4.x, p4.y, radi, p);
if (pic == null) {
pic = new PointF();
pic = p4;
price = x4;
}
break;
case 5:
drawLine(canvas, p);
canvas.drawCircle(p1.x, p1.y, radi, p);
canvas.drawCircle(p2.x, p2.y, radi, p);
canvas.drawCircle(p3.x, p3.y, radi, p);
canvas.drawCircle(p4.x, p4.y, radi, p);
canvas.drawCircle(p5.x, p5.y, radi, p);
if (pic == null) {
pic = new PointF();
pic = p5;
price = x5;
}
break;
}
} catch (Exception e) {
e.printStackTrace();
} /** 画圆角矩形 */
if (pic != null) {
// p = new Paint();
p.setAntiAlias(true);// 设置画笔的锯齿效果
p.setPathEffect(new PathEffect());
p.setColor(getResources().getColor(R.color.green_chart_dark));
textWidth = getTextWidth(p, String.format("%.2f", price));
left = pic.x - textWidth / 2;
top = pic.y - 35 * multi;
right = pic.x + textWidth / 2 + 5;
bottom = pic.y - 15 * multi;
RectF oval3 = new RectF(left, top, right, bottom);// 设置个新的长方形
canvas.drawRoundRect(oval3, 10, 10, p);// 第二个參数是x半径。第三个參数是y半径
path.moveTo(pic.x, pic.y - 5 * multi);
path.lineTo((left + right) / 2 - 5 * multi, bottom);
path.lineTo((left + right) / 2 + 5 * multi, bottom);
path.lineTo(pic.x, pic.y - 5 * multi);
canvas.drawPath(path, p);
p.setColor(Color.WHITE);
p.setTextSize(14 * multi);
canvas.drawText(String.format("%.2f", price), pic.x - textWidth / 2 + 5, pic.y - 20 * multi, p);
} if (hasAnim) {
handler.sendEmptyMessageDelayed(0, miles);
}
} public static int getTextWidth(Paint paint, String str) {
int iRet = 0;
if (str != null && str.length() > 0) {
int len = str.length();
float[] widths = new float[len];
paint.getTextWidths(str, widths);
for (int j = 0; j < len; j++) {
iRet += (int) Math.ceil(widths[j]);
}
}
return iRet;
} @Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
reFreshPic(event);
break;
case MotionEvent.ACTION_DOWN:
reFreshPic(event);
break;
case MotionEvent.ACTION_UP:
reFreshPic(event);
break;
} return super.onTouchEvent(event);
} private void reFreshPic(MotionEvent event) {
float x = event.getX();
int[] location = new int[2];
this.getLocationOnScreen(location);
float offsetX = x - widthText - widthHead;
if (offsetX < widthReal / 8) {
pic = p1;
price = x1;
} else if (offsetX > widthReal / 8 && offsetX < widthReal * 3 / 8) {
pic = p2;
price = x2;
} else if (offsetX > widthReal * 3 / 8 && offsetX < widthReal * 5 / 8) {
pic = p3;
price = x3;
} else if (offsetX > widthReal * 5 / 8 && offsetX < widthReal * 7 / 8) {
pic = p4;
price = x4;
} else if (offsetX > widthReal * 7 / 8) {
pic = p5;
price = x5;
}
this.invalidate();
} /**
* 依据传入的价格得到须要展示在view中的Y坐标
*
* max:最大值 min:最小值 height:图表的高度
*
* @param x
* @return
*/
public double getHeight(double x) {
if (max - min == 0) {
return 0;
} else {
return (max - x) / (max - min) * heightReal;
}
} public void drawLine(Canvas canvas, Paint p) {
switch (mChartBeanList.size()) {
case 0:
break;
case 1:
break;
case 2:
if (hasAnim) {
if (x1Complete) {
canvas.drawLine(p1.x, p1.y, p2x, p2y, p);
}
} else {
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, p);
}
break;
case 3:
if (hasAnim) {
if (x1Complete) {
canvas.drawLine(p1.x, p1.y, p2x, p2y, p);
}
if (x2Complete) {
canvas.drawLine(p2x, p2y, p3x, p3y, p);
}
} else {
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, p);
canvas.drawLine(p2.x, p2.y, p3.x, p3.y, p);
}
break;
case 4:
if (hasAnim) {
if (x1Complete) {
canvas.drawLine(p1.x, p1.y, p2x, p2y, p);
}
if (x2Complete) {
canvas.drawLine(p2x, p2y, p3x, p3y, p);
}
if (x3Complete) {
canvas.drawLine(p3x, p3y, p4x, p4y, p);
}
} else {
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, p);
canvas.drawLine(p2.x, p2.y, p3.x, p3.y, p);
canvas.drawLine(p3.x, p3.y, p4.x, p4.y, p);
}
break;
case 5:
if (hasAnim) {
if (x1Complete) {
canvas.drawLine(p1.x, p1.y, p2x, p2y, p);
}
if (x2Complete) {
canvas.drawLine(p2x, p2y, p3x, p3y, p);
}
if (x3Complete) {
canvas.drawLine(p3x, p3y, p4x, p4y, p);
}
if (x4Complete) {
canvas.drawLine(p4x, p4y, p5x, p5y, p);
}
} else {
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, p);
canvas.drawLine(p2.x, p2.y, p3.x, p3.y, p);
canvas.drawLine(p3.x, p3.y, p4.x, p4.y, p);
canvas.drawLine(p4.x, p4.y, p5.x, p5.y, p);
}
break;
}
} class MyHandler extends Handler {
public MyHandler() {
} public MyHandler(Looper L) {
super(L);
} @Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (p2x < p2.x) {
p2x = p2x + px;
p2y = p2y + (p2.y - p1.y) / (p2.x - p1.x) * px;
// pp2.x++;
// pp2.y = pp2.y + (p2.y - p1.y) / (p2.x - p1.x) * 1;
x1Complete = true;
ChartView.this.invalidate();
p3x = p2x;
System.out.println("p2y--" + p2y);
p3y = p2y;
} else if (p3x < p3.x) {
p3x = p3x + px;
p3y = p3y + (p3.y - p2.y) / (p3.x - p2.x) * px;
System.out.println("2");
// pp3.x = pp3.x + 1;
// pp3.y = pp3.y + (p3.y - p2.y) / (p3.x - p2.x) * 1;
ChartView.this.invalidate();
x2Complete = true;
p4x = p3x;
p4y = p3y;
} else if (p4x < p4.x) {
System.out.println("3");
p4x = p4x + px;
p4y = p4y + (p4.y - p3.y) / (p4.x - p3.x) * px;
// pp4.x = pp4.x + 1;
// pp4.y = pp4.y + (p4.y - p3.y) / (p4.x - p3.x) * 1;
ChartView.this.invalidate();
x3Complete = true;
p5x = p4x;
p5y = p4y;
} else if (p5x < p5.x) {
p5x = p5x + px;
System.out.println("4");
p5y = p5y + (p5.y - p4.y) / (p5.x - p4.x) * px;
// pp5.x = pp5.x + 1;
// pp5.y = pp5.y + (p5.y - p4.y) / (p5.x - p4.x) * 1;
ChartView.this.invalidate();
x4Complete = true;
} else {
System.out.println("return");
return;
}
}
}
}

https://github.com/yocn/chartView​

版权声明:本文博客原创文章,博客,未经同意,不得转载。

使用Canvas和Paint自己绘制折线图的更多相关文章

  1. Android自己定义组件系列【9】——Canvas绘制折线图

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了非常多插件,可是非常多时候我们须要依据详细项目自己定义这些图表,这一篇文章我们一起来看看怎样在Android中使用Can ...

  2. Android自定义控件 -Canvas绘制折线图(实现动态报表效果)

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas ...

  3. Android自定义组件系列【9】——Canvas绘制折线图

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas ...

  4. 用canvas绘制折线图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 【带着canvas去流浪】(2)绘制折线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 3.1 一般折线图 3.2 用贝塞尔曲线绘制平滑折线图 四. 大数据量场景 示例代码托管在:https://github.com/dashnowo ...

  6. 带着canvas去流浪系列之二 绘制折线图

    [摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  7. 【Canvas】(2)---绘制折线图

    绘制折线图 之前在工作的时候,用过百度的ECharts绘制折线图,上手很简单,这里通过canvas绘制一个简单的折线图.这里将一整个绘制过程分为几个步骤: 1.绘制网格 2.绘制坐标系 3.绘制点 4 ...

  8. html5绘制折线图

    html5绘制折线图详细代码 <html> <canvas id="a_canvas" width="1000" height="7 ...

  9. php中用GD绘制折线图

    php中用GD绘制折线图,代码如下: Class Chart{ private $image; // 定义图像 private $title; // 定义标题 private $ydata; // 定 ...

随机推荐

  1. mongoDB 批量更改数据,某个字段值等于另一个字段值

    由于mongodb数据库类似js的写法,所以即使数据库中新的列不存在也会自动创建 db.hospital.find().forEach( function(item){ db.hospital.upd ...

  2. 怎样在C++中获得完整的类型名称

    Wrote by mutouyun. (http://darkc.at/cxx-get-the-name-of-the-given-type/) 地球人都知道C++里有一个typeid操作符能够用来获 ...

  3. /etc/sysconfig/network-scripts/ifcfg-eth0

    以下各值常见于所有的基本配置文件中:* DEVICE=name,这里name是物理设备的名字(动态分配的PPP设备应当除外,它的名字是“逻辑名”.* IPADDR=addr, 这里addr是IP地址. ...

  4. JDK8在Java转让Javascript脚本引擎动态地定义和运行代码

    import java.lang.*; import java.util.Arrays; import java.util.List; import javax.script.Invocable; i ...

  5. An Overview of Complex Event Processing2

    An Overview of Complex Event Processing 翻译前言:感觉作者有点夸夸其谈兼絮絮叨叨,但文章还是很有用的.原文<An Overview of Complex ...

  6. hdu1005 Number Sequence(寻找循环节)

    主题链接: pid=1005">huangjing 题意: 就是给了一个公式,然后求出第n项是多少... 思路: 题目中n的范围实在是太大,所以肯定直接递推肯定会超时,所以想到的是暴力 ...

  7. 使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表

    原文:使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表 我们知道目标平台是32位的程序运行在64位的系统上,去访问部分注册表的时候系统自动重定向到win32node节点对应的 ...

  8. PHPCMS V9{loop subcat(0,0,0,$siteid) $r}怎么解释?

    {loop subcat(0,0,0,$siteid) $r}{/loop} /** * 获取子栏目  * @param $parentid 父级id   * @param $type 栏目类型  * ...

  9. SlopOne推荐算法

    在开源框架taste中有SlopOne的Java实现,效果不错.使用movielens的数据,代码例如以下 代码 #coding:utf-8 import re import math #读取数据,并 ...

  10. C++笔试面试总结

    手游广州某公司书面今天接受采访时.刚进去中午1中场休息.他们公司谁刚刚醒来,一个冷漠打牌,然后去上班.瞬间,这些公司有没有什么好印象,压抑. 接着快2点的时候.发了一份笔试题.大部分题目均在网上的&l ...