前两天修改一个项目的BUG:
使用hellocharts展示了一个饼图,点击饼图的一项再用折线图展示饼图中每项具体数据。
发现问题:饼图中现有数据,点击之后折线图不能展示数据。
通过查看数据源发现:不能展示图片的情况有两种:
1. 折线图所有数据一样:例:{7,7,7}
2. 折线图只有一个数据,例:{10}
通过debug调试发现:在计算RawX,RawY会出现pixelOffset为NaN的问题。
/**
* Translates chart value into raw pixel value. Returned value is absolute pixel X coordinate. If this method
* return
* 0 that means left most pixel of the screen.
*/
public float computeRawX(float valueX) {
// TODO: (contentRectMinusAllMargins.width() / currentViewport.width()) can be recalculated only when viewport
// change.
final float pixelOffset = (valueX - currentViewport.left) * (contentRectMinusAllMargins.width() /
currentViewport.width());
return contentRectMinusAllMargins.left + pixelOffset;
}
/**
* Translates chart value into raw pixel value. Returned value is absolute pixel Y coordinate. If this method
* return
* 0 that means top most pixel of the screen.
*/
public float computeRawY(float valueY) {
final float pixelOffset = (valueY - currentViewport.bottom) * (contentRectMinusAllMargins.height() /
currentViewport.height());
return contentRectMinusAllMargins.bottom - pixelOffset;
}
先看如何让解决问题2的:
当所有点都一样的时候:computeRawY会为NaN,原因是:
private void calculateMaxViewport() {
tempMaximumViewport.set(Float.MAX_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MAX_VALUE);
LineChartData data = dataProvider.getLineChartData();
for (Line line : data.getLines()) {
// Calculate max and min for viewport.
for (PointValue pointValue : line.getValues()) {
if (pointValue.getX() < tempMaximumViewport.left) {
tempMaximumViewport.left = pointValue.getX();
}
if (pointValue.getX() > tempMaximumViewport.right) {
tempMaximumViewport.right = pointValue.getX();
}
if (pointValue.getY() < tempMaximumViewport.bottom) {
tempMaximumViewport.bottom = pointValue.getY();
}
if (pointValue.getY() > tempMaximumViewport.top) {
tempMaximumViewport.top = pointValue.getY();
}
}
}
}
这个方法计算Y轴最大值最小值,当所有数据一样,计算出的bottom和top相等,导致
computeRawY中currentViewport.height()获取的值为0;所以修改如下:
private void calculateMaxViewport() {
tempMaximumViewport.set(Float.MAX_VALUE, Float.MIN_VALUE, Float.MIN_VALUE, Float.MAX_VALUE);
LineChartData data = dataProvider.getLineChartData();
for (Line line : data.getLines()) {
// Calculate max and min for viewport.
for (PointValue pointValue : line.getValues()) {
if (pointValue.getX() < tempMaximumViewport.left) {
tempMaximumViewport.left = pointValue.getX();
}
if (pointValue.getX() > tempMaximumViewport.right) {
tempMaximumViewport.right = pointValue.getX();
}
if (pointValue.getY() < tempMaximumViewport.bottom) {
tempMaximumViewport.bottom = pointValue.getY();
}
if (pointValue.getY() > tempMaximumViewport.top) {
tempMaximumViewport.top = pointValue.getY();
}
}
}
if (tempMaximumViewport.top == tempMaximumViewport.bottom) {//解决最大值最小值相等时,图不能展示问题
tempMaximumViewport.top = tempMaximumViewport.top * 2;
tempMaximumViewport.bottom = 0;
}
}
这样所有值都相等,可以在图中间画出一条直线。
再看问题一:
由于只有一个点,computeRawX中的currentViewport.width()为初始值,即min,这样computeRawX中的currentViewport算出来同样为NaN,修改代码如下:
public float computeRawX(float valueX) {
// TODO: (contentRectMinusAllMargins.width() / currentViewport.width()) can be recalculated only when viewport
// change.
final float pixelOffset = (valueX - currentViewport.left) * (contentRectMinusAllMargins.width() /
currentViewport.width());
if (Float.isNaN(pixelOffset)||Float.isInfinite(pixelOffset)) {
return contentRectMinusAllMargins.left + 0;
}
return contentRectMinusAllMargins.left + pixelOffset;
}
判断当算出的pixelOffset为NaN的时候直接返回contentRectMinusAllMargins.left。
好了以上两处修改就能解决折线图由于特殊数据(一条数据/数据相同)时不能展示的问题。
看上去修改的代码很简单,其实这里主要是源码的阅读和代码的跟踪。如何找到这两处还是花费了不少时间和精力的。
所以记下来,以供同样出现此问题的朋友参考。