MPAndroidChart之LinChart(3)scale缩放
来源:互联网 发布:淘宝应该怎么做 编辑:程序博客网 时间:2024/06/16 05:27
MPAndroidChart系列:
MPAndroidChart 之LineChart(1)
MPAndroidChart之LineChart(2)MarkerView
MPAndroidChart之LinChart(3)scale缩放
MPAndroidChart LineChart 缩放
MPAndroidChart使用版本:
对于MPAndroidChart 折线图的基本设置和属性不懂得建议先去了解也可以看这篇MPAndroidChart 之LineChart(1)。如果对最新版本使用过并且有点熟悉的话,我们接下来看看最新版本中折线图的缩放。
下面都是以LineChart为例子 下面都是以LineChart为例子 下面都是以LineChart为例子
1、为什么要缩放?
答:看上面的截图,借用官方的demo截的图,第一幅是数据大小挺合适的时候,第二幅是数据超级多的时候,什么感觉?明白缩放能干嘛了吗?当然是为了解决上面的这种数据过多,一屏显示不下问题,提高用户体验。
2、缩放是什么样子的?
答:上面就是对X轴进行了缩放一定比例,然后你就可以左右拖动了,就算数据再多也不怕密密麻麻了,当然你也可以对Y轴进行缩放,那样就能上下拖动。
3、怎么设置缩放?
答:我们可以 1)双击进行缩放;
2)手势双指缩放;
3)通过代码进行设置缩放。
下面是在缩放前可以选择设置的些我们需要设置的属性:
一、例子
这里以一种情况为例:不能双击缩放,不能手势手指缩放,只能通过代码设置固定的缩放
基础属性的设置自己去了解,下面只是是缩放代码设置
在最新版本里(当前是3.0.2),LineChart设置好基础属性后(如果基本设置和属性不懂的可以看看MPAndroidChart 之LineChart(1)),在按上面代码其中之一进行设置缩放3f后(这里为了简单些,只缩放X轴),效果图如下:
蛋疼的地方来了,大家系好安全带,因为下面全是解决缩放问题的东西,而且篇幅也不会很短,我尽可能写得详细点。
上面gif图我代码设置了X轴缩放是3f,单纯的我以为设置了缩放就能达到我想要的预期效果了,我认为的预期效果如下图
如果眼睛近视程度没有很深的话,上面两幅gif图区别还是能看出来的,不过我有个疑问,为什么设置了缩放后(从这里倒数第二幅gif图)是那样的,而不是我预期的那样(从这里倒数第一幅gif图)? --- 哎 也无所谓了,太多需求不一样吧。
实现了预期效果后看起来好简单,可是走过的路确是那么的艰难和漫长,官网没有提供好点的demo,博客10篇9篇是转载或乱七八糟的(也可能是我搜索关键词不对?),搜索后除了坑爹就剩下蛋疼,一脸茫然无助,只好自己研究研究了。
二、存在问题
X轴设置缩放后问题:
1、我们看到图表左右随着你拖动而拖动了,但是X轴的竖线(X轴竖下来的3条线)是定死的,不管怎样左右拖动,图表是动了但是那3条竖线没动,而是一直固定在那里;
2、当左右拖动时,X轴的label(也就是字符串1、字符串2、字符串3....)只是改变了数值,也没有和图表一起联动起来;
3、.....你来提....
三、解决问题
解决问题1步骤:
1、初始化chart基本属性
首先是把LineChart基本属性设置了,这里如果还不清楚一些基本属性设置的话,可以看看MPAndroidChart 之LineChart(1),然后记得要设置缩放的倍数,设置好后大概就像下面的gif图一样,当然,数据不一样没什么影响,关键是效果一样,OK;
2、从何处入手
从哪里入手呢?在MPAndroidChart中有一个类“AxisRenderer”,翻译过来Axis就是渲染器的意思,该类是干什么的,你可以点击进去查看源码有哪些方法并且做了什么,也可以看官方给的doc中查看该类做什么的,前往官方doc,如下图,官方对“AxisRenderer”类说得很清楚了,下图中是该累拥有的方法,并且说明了每个方法做了什么(看不懂英文就去在线翻译),其中看到1个我圈出来的方法,也就是我解决上面提到存在问题1的关键方法
我为什么知道该类?首先我是一步一步来的并且在我这篇”MPAndroidChart 之LineChart(1)博客中,解决了几个问题(主要是X轴第一个和最后一个label超出了Y轴的左右两边的轴线),自然而然就知道“AxisRenderer”类的存在并且有哪些方法,能干嘛的了
继承“AxisRenderer”有“XAxisRenderer”和“YAxisRenderer”2个类,这里要解决的问题,只用到“XAxisRenderer”类(也就是解决问题1和2都是是属于X轴的东西嘛),OK
下面是源码AxisRenderer类里的renderGridLines方法,方法里面也是源码代码,经过打印测试,我把重要的地方都注释有了
代码:
// x轴垂直竖线线 @Override public void renderGridLines(Canvas c) { //源码 if (!mXAxis.isDrawGridLinesEnabled() || !mXAxis.isEnabled()) return; int clipRestoreCount = c.save(); c.clipRect(getGridClippingRect()); //if保证mRenderGridLinesBuffer长度为X轴标签数乘以2(mAxis.mEntryCount为label数) if (mRenderGridLinesBuffer.length != mAxis.mEntryCount * 2) { mRenderGridLinesBuffer = new float[mXAxis.mEntryCount * 2]; } float[] positions = mRenderGridLinesBuffer; //mEntries数组里面装的是x轴setValueFormatter里的value中从最小到大开始取的值 for (int i = 0; i < positions.length; i += 2) { positions[i] = mXAxis.mEntries[i / 2]; positions[i + 1] = mXAxis.mEntries[i / 2]; } //用所有矩阵变换点数组。非常重要:保持矩阵顺序“值触摸偏移”时转化。 mTrans.pointValuesToPixel(positions); //设置画笔属性 setupGridPaint(); Path gridLinePath = mRenderGridLinesPath; gridLinePath.reset(); for (int i = 0; i < positions.length; i += 2) { //根据positions数组里的值画出X轴竖线 drawGridLine(c, positions[i], positions[i + 1], gridLinePath); } c.restoreToCount(clipRestoreCount); }
上面是官方画X轴标签竖线的源码,可以看到思路:1)创建一个标签数乘以2大小的数组;
2)把需要画的竖线的位置数据赋值给positions数组;
3)调用mTrans.pointValuesToPixel(positions)方法把数组positions里的数据变换;
4)根据mTrans.pointValuesToPixel(positions)方法变换好的数据,调用drawGridLine方法,把竖线画出来。
ok,这样画出来的Chart,如果设置了X轴缩放大小,X轴的竖线是固定的,并不随左右拖动而拖动(也就是竖线并没有缩放),也就会存在前面说的问题1,如下gif图
存在这样的问题,原因就在于源码是设置完数组positions数据后(这就等于固定了X轴竖线的位置了,同时也代表positions里的数据是不缩放的值)才调用mTrans.pointValuesToPixel(positions)方法。
3、具体解决问题1
上面我应该算很清楚的注释了,要解决问题1,最重要的是mTrans.pointValuesToPixel(positions)方法,点击进入源码我们看到如下图
翻译过来如下图
恩,也就是说我想要竖线不固定(随着X轴缩放竖线也缩放)那就得调下顺序,得设置一条竖线的数据(每条线的数据就得自己摸索了)就调用mTrans.pointValuesToPixel(positions)方法,然后在调用drawGridLine方法画出来(和源码设置完所有竖线数据在调用mTrans.pointValuesToPixel(positions)和drawGridLine不一样)。
想要看得懂后面的某段代码,下面例子一定要看明白。。。。。。。。。。。。。。。。。。。。。。。。。。。。
每条线数据例子:
如下图,有一根线,现在只知道第一个刻度和最后一个刻度值为1和17,每个刻度是平均分的,现在我要求出打问号的另外3个刻度的值,怎么算呢?
第一个问号:((17-1)/4)*1+1; (最后一个值-第一个值)
第二个问号:((17-1)/4)*2+1; ========》得出公式:每个刻度值 = [--------------------------------------]*下标+第一个值;
第三个问号:((17-1)/4)*3+1; 份数(多少份)
上面的例子和公式对于下面修改源码中如何获取每条线X轴坐标值思路基本是一样的。
恩,按照这个思路我们修改一下下源码,先写个类MyXAxisRenderer继承XAxisRenderer类,然后重写renderGridLines方法
代码
import android.graphics.Canvas;import android.graphics.Path;import com.github.mikephil.charting.components.XAxis;import com.github.mikephil.charting.renderer.XAxisRenderer;import com.github.mikephil.charting.utils.ViewPortHandler;import com.mpandroidchartcsdn.mychart.MyLineChart;import static android.R.attr.label;public class MyXAxisRenderer extends XAxisRenderer { private MyLineChart myLineChart; public MyXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans, MyLineChart myLineChart) { super(viewPortHandler, xAxis, trans); this.myLineChart = myLineChart; } // x轴垂直线 @Override public void renderGridLines(Canvas c) { //源码拷贝过来 if (!mXAxis.isDrawGridLinesEnabled() || !mXAxis.isEnabled()) return; int clipRestoreCount = c.save(); c.clipRect(getGridClippingRect()); //if保证mRenderGridLinesBuffer长度为X轴标签数乘以2(mAxis.mEntryCount为label数) if (mRenderGridLinesBuffer.length != mAxis.mEntryCount * 2) { mRenderGridLinesBuffer = new float[mXAxis.mEntryCount * 2]; } float[] positions = mRenderGridLinesBuffer; //mEntries数组里面装的是x轴setValueFormatter里的value中从最小到大开始取的值 for (int i = 0; i < positions.length; i += 2) { positions[i] = mXAxis.mEntries[i / 2]; positions[i + 1] = mXAxis.mEntries[i / 2]; } /* //用所有矩阵变换点数组。非常重要:保持矩阵顺序“值触摸偏移”时转化。 mTrans.pointValuesToPixel(positions);*/ //设置画笔属性 setupGridPaint(); Path gridLinePath = mRenderGridLinesPath; gridLinePath.reset(); for (int i = 0; i < positions.length; i += 2) { /* * 最后一个坐标X坐标值-第一个坐标X坐标值 * X轴竖线X坐标 = (---------------------------------------------)*(i/2)+第一个坐标X坐标值 * label-1 */ //下面4行是调整的代码 //第一个坐标X坐标值 float fX = myLineChart.getData().getDataSets().get(0).getEntryForIndex(0).getX(); //最后一个坐标X坐标值 float eX = myLineChart.getData().getDataSets().get(0).getEntryForIndex(myLineChart.getData().getEntryCount() - 1).getX(); positions[i] = ((eX - fX) / (mXAxis.mEntryCount - 1)) * (i / 2) + (fX); mTrans.pointValuesToPixel(positions); //根据positions数组里的值画出X轴竖线 drawGridLine(c, positions[i], positions[i + 1], gridLinePath); } c.restoreToCount(clipRestoreCount); }
然后在创建一个MyLineChart
代码
package com.mpandroidchartcsdn.mychart; import android.content.Context; import android.util.AttributeSet; import com.github.mikephil.charting.charts.LineChart;/** * Created by tujingwu on 2017/5/4 * . */public class MyLineChart extends LineChart { public MyLineChart(Context context) { super(context); } public MyLineChart(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void init() { super.init(); mXAxisRenderer = new MyXAxisRenderer(mViewPortHandler, mXAxis, mLeftAxisTransformer,this); }}
最后像使用LineChart一样使用MyLineChart就行了,最后gif结果图如下
ok,对于X轴的竖线已经解决了问题1,也达到了预期效果,对于问题2,也就是X轴的标签,那就更好解决了,同样的道理。
解决问题2步骤:
1、先写个类MyXAxisRenderer继承XAxisRenderer类,然后重写drawLabels方法
代码
package com.mpandroidchartcsdn.mychart;import android.graphics.Canvas;import com.github.mikephil.charting.components.XAxis;import com.github.mikephil.charting.renderer.XAxisRenderer;import com.github.mikephil.charting.utils.MPPointF;import com.github.mikephil.charting.utils.Transformer;import com.github.mikephil.charting.utils.Utils;import com.github.mikephil.charting.utils.ViewPortHandler;public class MyXAxisRenderer extends XAxisRenderer { private MyLineChart myLineChart; public MyXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans, MyLineChart myLineChart) { super(viewPortHandler, xAxis, trans); /* this.mChart = mChart; this.mXAxis = xAxis;*/ this.myLineChart = myLineChart; } @Override protected void drawLabels(Canvas c, float pos, MPPointF anchor) { //把代码复制过来 final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle(); boolean centeringEnabled = mXAxis.isCenterAxisLabelsEnabled(); float[] positions = new float[mXAxis.mEntryCount * 2]; for (int i = 0; i < positions.length; i += 2) { // only fill x values if (centeringEnabled) { positions[i] = mXAxis.mCenteredEntries[i / 2]; } else { positions[i] = mXAxis.mEntries[i / 2]; } } // mTrans.pointValuesToPixel(positions); for (int i = 0; i < positions.length; i += 2) { float x = positions[i]; if (mViewPortHandler.isInBoundsX(x)) { String label = mXAxis.getValueFormatter().getFormattedValue(mXAxis.mEntries[i / 2], mXAxis); if (mXAxis.isAvoidFirstLastClippingEnabled()) { // avoid clipping of the last mXAxis.mEntryCount-1为x轴标签数 if (i == mXAxis.mEntryCount - 1 && mXAxis.mEntryCount > 1) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); if (width > mViewPortHandler.offsetRight() * 2 && x + width > mViewPortHandler.getChartWidth()) x -= width / 2; // avoid clipping of the first } else if (i == 0) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); x += width / 2; } } drawLabel(c, label, positions[0], pos, anchor, labelRotationAngleDegrees); } } }}
2、思路还是和解决问题1一样,稍微修改一下下源码,上面代码修改后
代码
import android.graphics.Canvas;import com.github.mikephil.charting.components.XAxis;import com.github.mikephil.charting.renderer.XAxisRenderer;import com.github.mikephil.charting.utils.MPPointF;import com.github.mikephil.charting.utils.Utils;import com.github.mikephil.charting.utils.ViewPortHandler;import com.mpandroidchartcsdn.mychart.MyLineChart;import static android.R.attr.x;public class MyXAxisRenderer extends XAxisRenderer { private MyLineChart myLineChart; public MyXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans, MyLineChart myLineChart) { super(viewPortHandler, xAxis, trans); this.myLineChart = myLineChart; } @Override protected void drawLabels(Canvas c, float pos, MPPointF anchor) { //把代码复制过来 final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle(); boolean centeringEnabled = mXAxis.isCenterAxisLabelsEnabled(); float[] positions = new float[mXAxis.mEntryCount * 2]; for (int i = 0; i < positions.length; i += 2) { // only fill x values if (centeringEnabled) { positions[i] = mXAxis.mCenteredEntries[i / 2]; } else { positions[i] = mXAxis.mEntries[i / 2]; } } // mTrans.pointValuesToPixel(positions); for (int i = 0; i < positions.length; i += 2) { /* * 最后一个坐标X坐标值-第一个坐标X坐标值 * X轴竖线X坐标 = (---------------------------------------------)*(i/2)+第一个坐标X坐标值 * label-1 */ //下面四行是修改后的代码 //第一个坐标X坐标值 float fX = myLineChart.getData().getDataSets().get(0).getEntryForIndex(0).getX(); //最后一个坐标X坐标值 float eX = myLineChart.getData().getDataSets().get(0).getEntryForIndex(myLineChart.getData().getEntryCount() - 1).getX(); positions[i] = ((eX - fX) / (mXAxis.mEntryCount - 1)) * (i / 2) + (fX); mTrans.pointValuesToPixel(positions); if (mViewPortHandler.isInBoundsX(positions[i])) { String label = mXAxis.getValueFormatter().getFormattedValue(mXAxis.mEntries[i / 2], mXAxis); if (mXAxis.isAvoidFirstLastClippingEnabled()) { // avoid clipping of the last mXAxis.mEntryCount-1为x轴标签数 if (i == mXAxis.mEntryCount - 1 && mXAxis.mEntryCount > 1) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); if (width > mViewPortHandler.offsetRight() * 2 && x + width > mViewPortHandler.getChartWidth()) positions[i] -= width / 2; // avoid clipping of the first } else if (i == 0) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); positions[i] += width / 2; } } drawLabel(c, label, positions[i], pos, anchor, labelRotationAngleDegrees); } } }}
3、创建一个MyLineChart
代码
package com.mpandroidchartcsdn.mychart; import android.content.Context; import android.util.AttributeSet; import com.github.mikephil.charting.charts.LineChart;/** * Created by tujingwu on 2017/5/4 * . */public class MyLineChart extends LineChart { public MyLineChart(Context context) { super(context); } public MyLineChart(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void init() { super.init(); mXAxisRenderer = new MyXAxisRenderer(mViewPortHandler, mXAxis, mLeftAxisTransformer,this); }}
最后运行效果如下gif图
这样一来上面存在的2个问题都得的解决后,得到下面最终gif图
总结:对于缩放最终得到解决,给我的一些思路还是来自http://blog.csdn.net/qqyanjiang/article/details/51442120这位兄弟的博客,虽然博客里没有怎么详细说,不过还是提供了一些思路,现在解决了上面我提到的2个问题,后面有时间会把联动和蜡烛图也写了。
阅读全文
3 0
- MPAndroidChart之LinChart(3)scale缩放
- Mpandroidchart linchart属性
- iTween基础之Scale(缩放大小)
- iTween基础之Scale(缩放大小)
- iTween基础之Scale(缩放大小)
- 【CSS3】变形--缩放 scale()
- 变形--缩放 scale()
- 7:---(3)CSS3中的变形--缩放 scale()
- Canvas 学习之 (3) scale
- Android Canvas 缩放(Scale)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate)
- Android studio编译报错:Error:Execution failed for task ':app:transformClassesWithDexForDebug'
- 121Best Time to Buy and Sell Stock
- 支持向量机(SVM):基本原理
- 树莓派3B ssh登录 密码无限错误
- redis主从复制
- MPAndroidChart之LinChart(3)scale缩放
- IPC-命名管道(FIFO)
- Android 之 内存管理
- Maven Rollback a Release
- Android在Activity中获取手机屏幕的宽高
- oc中关于pch文件
- freemarker list (长度,遍历,下标,嵌套,排序)
- [李景山php] yaf 的运行流程图
- windows下修改host不生效的解决方法