MPAndroidChart之LineChart源码分析
2017-05-27 14:56
393 查看
LineChart比PieChart逻辑简单,主要技术点就是双指缩放逻辑。
方法3~10。是根据需要绘制数据的横(XAxis)纵(YAxis)轴的极限值,组装横坐标,纵坐标的刻度值。
方法11~13 计算图例,图表的上下左右的偏移量。
建议去看看方法7,还是觉得作者数学很好。计算整数间隔。向上取整,向下取整,判断一个数是几位数。
(2)X轴坐标线/Y轴坐标线
(3)X轴网格线/Y轴网格线
(4)X轴/Y轴极限辅助线
(5)X轴坐标值/Y轴坐标值
(5~6)数据1点/数据2点
(2)将坐标数值经过矩阵变化变成最终显示像素集合
(3)这里我以为作者还会延续path使用。将路线设定好在绘制。但是作者又来教做人了。作者采用了drawLines方法。API请见绘制多条直线的 drawLines方法
(14~15)markView绘制
Android多点触控。android触控,先了解MotionEvent。
Matrix矩阵变换Android Matrix详解
(1~13)初始化Matrix
(14~15)手势触发.变换Matrix
//进行坐标变化然后绘制
这边就是设置mMatrixTouch 手势缩放变换矩阵. 然后调用方法4绘制
//当move时,满足条件.会将mMatrixTouch进行矩阵缩放.要主意set.post.pre的区别
矩阵设置完成,会调用refresh里面的invalidate()方法通知ondraw重新绘制view.这样缩放逻辑就完成了.
Log:
1 数据准备
1.1 折线数据
1.1.1 坐标点对象Entry
参照构造函数,有两个参数:x,y对应横坐标和纵坐标的值。1.1.2 数据1对象/数据2对象 LineDataSet
参照构造函数,有两个参数:构成折线坐标点集合 List<Entry>yVals,这条折线的描述 label。还保存坐标点表现形式,坐标点颜色,半径等。1.1.3 线性图表对象LineData
参照构造函数,有一个参数:折线数据对象集合List<ILineDataSet > sets。1.2 绘制数据计算(按照代码执行顺序)
1.2.1 构造LineDataSet时找到折线对象中坐标点集合中横坐标和纵坐标的极限值。DataSet.mXMin、DataSet.mXMax、DataSet.mYMin、DataSet.mYMax
1.2.2 构造LineData时找到折线数组中折线经过横坐标和纵坐标的极限值ChartData.mMax、CartData.mMin、ChartData.mLeftAxisMax、ChartData.mLeftAxisMin
1.2.3 view绘制开始准备
方法1~2 view执行onMeasure后会触发onSizeChanged获得当前View长宽。方法3~10。是根据需要绘制数据的横(XAxis)纵(YAxis)轴的极限值,组装横坐标,纵坐标的刻度值。
方法11~13 计算图例,图表的上下左右的偏移量。
建议去看看方法7,还是觉得作者数学很好。计算整数间隔。向上取整,向下取整,判断一个数是几位数。
2 实现功能点
2.1 基本坐标系建立
(1) 图表底图(2)X轴坐标线/Y轴坐标线
(3)X轴网格线/Y轴网格线
(4)X轴/Y轴极限辅助线
(5)X轴坐标值/Y轴坐标值
2.2 数据绘制
(2~4)数据1折线/数据2折线(5~6)数据1点/数据2点
2.2.1 重新计算数据起止点
问题:我到现在也没有搞清楚作者为什么要写这个逻辑?有知道的大神可以给我留言告诉我public void set(BarLineScatterCandleBubbleDataProvider chart, IBarLineScatterCandleBubbleDataSet dataSet) { float phaseX = Math.max(0.f, Math.min(1.f, mAnimator.getPhaseX())); float low = chart.getLowestVisibleX(); //mXAxis.mAxisMinimum float high = chart.getHighestVisibleX(); //mXAxis.mAxisMaximum Entry entryFrom = dataSet.getEntryForXValue(low, Float.NaN, DataSet.Ro 4000 unding.DOWN); Entry entryTo = dataSet.getEntryForXValue(high, Float.NaN, DataSet.Rounding.UP); min = entryFrom == null ? 0 : dataSet.getEntryIndex(entryFrom); max = entryTo == null ? 0 : dataSet.getEntryIndex(entryTo); range = (int) ((max - min) * phaseX); }
2.2.2 绘制折线(方法4)
(1)数学概念:两点确定一条直线。LineBuffer集合必须要有4个数据。0,1代表开始点坐标值;2,3代表结束点的坐标值。(2)将坐标数值经过矩阵变化变成最终显示像素集合
(3)这里我以为作者还会延续path使用。将路线设定好在绘制。但是作者又来教做人了。作者采用了drawLines方法。API请见绘制多条直线的 drawLines方法
for (int j = mXBounds.min; j <= mXBounds.range + mXBounds.min; j++) { Entry e = dataSet.getEntryForIndex(j); if (e == null) continue; mLineBuffer[0] = e.getX(); mLineBuffer[1] = e.getY() * phaseY; if (j < mXBounds.max) { e = dataSet.getEntryForIndex(j + 1); if (e == null) break; mLineBuffer[2] = e.getX(); mLineBuffer[3] = e.getY() * phaseY; } else { mLineBuffer[2] = mLineBuffer[0]; mLineBuffer[3] = mLineBuffer[1]; } trans.pointValuesToPixel(mLineBuffer); canvas.drawLines(mLineBuffer, 0, pointsPerEntryPair * 2, mRenderPaint); }
2.2.3 绘制数据坐标点(方法7,8)
(1) 创建数据点位图集合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; }(2)以数据点位图为画布,绘制圆形位图
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)); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(set.getCircleColor(i)); paint.setAntiAlias(true); canvas.drawCircle( circleRadius, circleRadius, circleRadius, paint); } }(3) 把数据点位图绘制到坐标系画布上。
protected void drawCircles(Canvas c) { Bitmap circleBitmap = imageCache.getBitmap(j); if (circleBitmap != null) { c.drawBitmap(circleBitmap, mCirclesBuffer[0] - circleRadius, mCirclesBuffer[1] - circleRadius, mRenderPaint); } }
2.3 触摸mark绘制
(12~13)坐标点辅助线绘制(14~15)markView绘制
3 双指缩放
首先又涉及到基本知识。Android多点触控。android触控,先了解MotionEvent。
Matrix矩阵变换Android Matrix详解
(1~13)初始化Matrix
(14~15)手势触发.变换Matrix
3.1(1~13)初始化Matrix
初始化就不详细介绍了.给大家展示一下日志mMatrixValueToPx 坐标系原始矩阵(不改变)mMatrixOffests 坐标系偏移量矩阵(不改变)mMatrixTouch 手势缩放变换矩阵E/mmnn ( 2441): init mMatrix = Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} E/mmnn ( 2441): onSizChanged E/mmnn ( 2441): refresh mMatrixTouch = Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} E/mmnn ( 2441): notifyDataSetChanged E/mmnn ( 2441): calculateOffsets E/mmnn ( 2441): calculateOffsets mMatrixOffset = Matrix{[1.0, 0.0, 39.0][0.0, 1.0, 922.4219][0.0, 0.0, 1.0]} E/mmnn ( 2441): calculateOffsets mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]} E/mmnn ( 2441): calculateOffsets mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]}
3.2 绘制坐标系(2.2方法方法4为例)
//构造绘制集合//进行坐标变化然后绘制
protected void drawLinear(Canvas c, ILineDataSet dataSet) { for (int j = mXBounds.min; j <= mXBounds.range + mXBounds.min; j++) { trans.pointValuesToPixel(mLineBuffer); } canvas.drawLines(mLineBuffer, 0, size, mRenderPaint); }以第0个点为例
E/mmnn ( 2441): pts0.0 E/mmnn ( 2441): mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]} pts0.0 E/mmnn ( 2441): mMatrixTouch = Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} pts0.0 E/mmnn ( 2441): mMatrixOffset = Matrix{[1.0, 0.0, 39.0][0.0, 1.0, 922.4219][0.0, 0.0, 1.0]} pts39.03.3手势控制变换刷新矩阵(方法14,15)
这边就是设置mMatrixTouch 手势缩放变换矩阵. 然后调用方法4绘制
public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: saveTouchStart(event); break; case MotionEvent.ACTION_POINTER_DOWN: if (event.getPointerCount() >= 2) { saveTouchStart(event); } mTouchMode = X_ZOOM; break; case MotionEvent.ACTION_MOVE: performZoom(event); break; case MotionEvent.ACTION_UP: mChart.calculateOffsets(); mChart.postInvalidate(); mTouchMode = NONE; break; case MotionEvent.ACTION_POINTER_UP: mTouchMode = POST_ZOOM; break; case MotionEvent.ACTION_CANCEL: mTouchMode = NONE; break; } mMatrix = mChart.getViewPortHandler().refresh(mMatrix, mChart, true); return true; }
//当move时,满足条件.会将mMatrixTouch进行矩阵缩放.要主意set.post.pre的区别
private void performZoom(MotionEvent event) { mMatrix.set(mSavedMatrix); mMatrix.postScale(scaleX, 1f, t.x, t.y); }
矩阵设置完成,会调用refresh里面的invalidate()方法通知ondraw重新绘制view.这样缩放逻辑就完成了.
Log:
E/mmnn ( 2441): ACTION_DOWN
E/mmnn ( 2441): refresh mMatrixTouch = Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
E/mmnn ( 2441): pts0.0 E/mmnn ( 2441): mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]} pts0.0 E/mmnn ( 2441): mMatrixTouch = Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} pts0.0 E/mmnn ( 2441): mMatrixOffset = Matrix{[1.0, 0.0, 39.0][0.0, 1.0, 922.4219][0.0, 0.0, 1.0]} pts39.0
E/mmnn ( 2441): ACTION_MOVE
E/mmnn ( 2441): performZoom X_ZOOM mMatrix = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
E/mmnn ( 2441): refresh mMatrixTouch = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
E/mmnn ( 2441): pts0.0
E/mmnn ( 2441): mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]} pts0.0
E/mmnn ( 2441): mMatrixTouch = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} pts-87.966156
E/mmnn ( 2441): mMatrixOffset = Matrix{[1.0, 0.0, 39.0][0.0, 1.0, 922.4219][0.0, 0.0, 1.0]} pts-48.966156
E/mmnn ( 2441): ACTION_POINTER_UP
E/mmnn ( 2441): refresh mMatrixTouch = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
E/mmnn ( 2441): pts0.0
E/mmnn ( 2441): mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]} pts0.0
E/mmnn ( 2441): mMatrixTouch = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} pts-87.966156
E/mmnn ( 2441): mMatrixOffset = Matrix{[1.0, 0.0, 39.0][0.0, 1.0, 922.4219][0.0, 0.0, 1.0]} pts-48.966156
E/mmnn ( 2441): ACTION_UP
E/mmnn ( 2441): calculateOffsets
E/mmnn ( 2441): calculateOffsets mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]}
E/mmnn ( 2441): calculateOffsets mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]}
E/mmnn ( 2441): refresh mMatrixTouch = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
E/mmnn ( 2441): pts0.0
E/mmnn ( 2441): mMatrixValueToPx = Matrix{[37.944443, 0.0, 0.0][0.0, -1.4998698, -74.99349][0.0, 0.0, 1.0]} pts0.0
E/mmnn ( 2441): mMatrixTouch = Matrix{[1.223548, 0.0, -87.966156][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} pts-87.966156
E/mmnn ( 2441): mMatrixOffset = Matrix{[1.0, 0.0, 39.0][0.0, 1.0, 922.4219][0.0, 0.0, 1.0]} pts-48.966156
4 拖拽和绘制动画
与MPAndroidChart类似,可以参考MPAndroidChart之PieChart源码分析相关文章推荐
- Android MPAndroidChart使用教程和源码分析(五)
- MPAndroidChart之PieChart源码分析
- Android MPAndroidChart使用教程和源码分析(二)
- MPAndroidChart系列源码解读(二)
- MPAndroidChart之LineChart使用
- MPAndroidChart系列源码解读(三)
- MPAndroidChart 之LineChart(1)
- MPAndroidChart之LineChart
- MPAndroidChart系列源码解读(五)
- 关于 MPAndroidChart 中的 LineChart 的使用小结
- MPAndroidChart之lineChart中的诡异属性
- MPAndroidChart之LineChart
- MPAndroidChart LineChart X轴标签显示问题
- MPAndroidChart之LineChart曲线型
- MPAndroidChart之LineChart(2)MarkerView
- MPAndroidChart的教程(一) LineChart的使用(by 星空武哥)
- AndroidMPChart学习之LineChart详细总结
- MPAndroidChart的LineChart的使用
- MPAndroidChart之LineChart双线绘制
- MpAndroidChart源码修改之饼状图添加标志线