MPAndroidChart系列:
MPAndroidChart 之LineChart(1)
MPAndroidChart之LineChart(2)MarkerView
MPAndroidChart之LinChart(3)scale缩放
这里以一种情况为例:不能双击缩放,不能手势手指缩放,只能通过代码设置固定的缩放
基础属性的设置自己去了解,下面只是是缩放代码设置
蛋疼的地方来了,大家系好安全带,因为下面全是解决缩放问题的东西,而且篇幅也不会很短,我尽可能写得详细点。
上面gif图我代码设置了X轴缩放是3f,单纯的我以为设置了缩放就能达到我想要的预期效果了,我认为的预期效果如下图
如果眼睛近视程度没有很深的话,上面两幅gif图区别还是能看出来的,不过我有个疑问,为什么设置了缩放后(从这里倒数第二幅gif图)是那样的,而不是我预期的那样(从这里倒数第一幅gif图)? --- 哎 也无所谓了,太多需求不一样吧。
实现了预期效果后看起来好简单,可是走过的路确是那么的艰难和漫长,官网没有提供好点的demo,博客10篇9篇是转载或乱七八糟的(也可能是我搜索关键词不对?),搜索后除了坑爹就剩下蛋疼,一脸茫然无助,只好自己研究研究了。
二、存在问题
X轴设置缩放后问题:
1、我们看到图表左右随着你拖动而拖动了,但是X轴的竖线(X轴竖下来的3条线)是定死的,不管怎样左右拖动,图表是动了但是那3条竖线没动,而是一直固定在那里;
2、当左右拖动时,X轴的label(也就是字符串1、字符串2、字符串3....)只是改变了数值,也没有和图表一起联动起来;
3、.....你来提....
三、解决问题
// 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);
}
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);
}
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);
}
}
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);
}
}
}
}
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);
}
}
}
}
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);
}
}