MPAndroidChart:在日期格式上将网格和标签对齐到午夜 (00:00)
MPAndroidChart: Justifiy grid and labels to midnight (00:00) on date formatting
问题:
MPAndroidChart 可以很好地计算十进制值的网格和标签位置,但对于 date/time 轴则不然。
我想让标签位置恰好在午夜对齐,例如。 x 轴范围为 4 天:
[26.1-00h, 27.1-00h, 28.1-00h,29.1-00h, 30.1-00h]
或者如果范围是例如。只有 2 天:
[26.1-00h, 26.1-12h, 27.1-00h, 27.1-12h,28.1-00h]
等等
我试过的:
调整了MPAndroidChart x-axis date/time label formatting的解决方案,但它不适用于MPAndroidChart的最新版本3.1.0。
使用 setAxisMinimum() 和 setAxisMaximum() 将图表最小值和最大值更正为午夜时间戳。
尝试不同的值缩放。
使用 setGranularity() 将粒度设置为一整天,但随后数据点会从其原始位置快速移动到粒度位置。
网格原点和间距的计算似乎是在 class AxisRenderer 的 computeAxisValues() 中完成的,但这class不能超载(?)
有没有办法在不改变库的情况下控制x轴标签的定位?
回答我自己的问题:
- 添加日期格式以及缩放常量:
private static final long MS_PER_XSCALE = 1000 * 60; // scale to minute resolution
private static final long XSCALE_ONE_DAY = 60 * 24; // one day
private final SimpleDateFormat xAxisDataFormat_DD_MMM_H = new SimpleDateFormat("dd.MMM'_'H'h'", Locale.ENGLISH);
private final SimpleDateFormat xAxisDataFormat_DD_MMM = new SimpleDateFormat("dd.MMM", Locale.ENGLISH);
private static final long TIMEOFFSET = TimeZone.getDefault().getRawOffset();
- 在 Activity:
的 onCreate() 中设置自定义日期轴渲染器和日期格式器
chart.setXAxisRenderer(new DateXAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(null)));
chart.getXAxis().setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
if ((int) value / XSCALE_ONE_DAY * XSCALE_ONE_DAY == value)
return xAxisDataFormat_DD_MMM.format(new Date((long) value * MS_PER_XSCALE - TIMEOFFSET));
else
return xAxisDataFormat_DD_MMM_H.format(new Date((long) value * MS_PER_XSCALE - TIMEOFFSET));
}
});
- 按如下方式实现日期轴渲染器:
class DateXAxisRenderer extends XAxisRenderer {
public DateXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {
super(viewPortHandler, xAxis, trans);
}
@Override
protected void computeAxisValues(float min, float max) {
int day_fraction[] = {1,2,3,4,6,8,12,24};
float interval=0;
int labelCount=0;
float xMin = min;
float xMax = max;
xMax -= xMax % XSCALE_ONE_DAY;
xMin += XSCALE_ONE_DAY - (xMin % XSCALE_ONE_DAY);
int days = (int) ((xMax - xMin) / XSCALE_ONE_DAY);
float days_interval = days / 3;
if (days_interval > 0) {
interval = days_interval * XSCALE_ONE_DAY;
labelCount = (int) ((xMax - xMin) / interval);
}
if (days_interval == 0 || labelCount<3) {
int i = day_fraction.length-1;
do {
xMax = max - max % (XSCALE_ONE_DAY / day_fraction[i]);
xMin = min + (XSCALE_ONE_DAY / day_fraction[i] - (min % (XSCALE_ONE_DAY / day_fraction[i])));
labelCount = (int) ((xMax - xMin) / (XSCALE_ONE_DAY / day_fraction[i]));
} while (labelCount > 4 && i-- > 0);
interval = (xMax - xMin) / labelCount;
}
if (labelCount == 0 /*|| range <= 0 || Double.isInfinite(range)*/) {
mAxis.mEntries = new float[]{};
mAxis.mCenteredEntries = new float[]{};
mAxis.mEntryCount = 0;
return;
}
labelCount++; // add last label
//Timber.i("corrected min:" + xMin + ", max:" + xMax + ", interval:" + interval + ", labelcount:" + labelCount);
mAxis.mEntries = new float[labelCount];
float v = xMin;
for (int i = 0; i < labelCount; i++) {
mAxis.mEntries[i] = v;
Timber.i("Label " + i + " at:" + mAxis.mEntries[i] + " day:" + mAxis.mEntries[i] / XSCALE_ONE_DAY);
v += interval;
}
//mAxis.setLabelCount(labelCount);
//mAxis.setGranularityEnabled(false);
mAxis.mEntryCount = labelCount;
}
}
就是这样!
备注:很好地呈现的范围是天到分钟,但如果您需要年、月或秒,您必须相应地调整格式化程序以及已实现的 computeAxisValues()。
问题:
MPAndroidChart 可以很好地计算十进制值的网格和标签位置,但对于 date/time 轴则不然。
我想让标签位置恰好在午夜对齐,例如。 x 轴范围为 4 天:
[26.1-00h, 27.1-00h, 28.1-00h,29.1-00h, 30.1-00h]
或者如果范围是例如。只有 2 天:
[26.1-00h, 26.1-12h, 27.1-00h, 27.1-12h,28.1-00h]
等等
我试过的:
调整了MPAndroidChart x-axis date/time label formatting的解决方案,但它不适用于MPAndroidChart的最新版本3.1.0。
使用 setAxisMinimum() 和 setAxisMaximum() 将图表最小值和最大值更正为午夜时间戳。
尝试不同的值缩放。
使用 setGranularity() 将粒度设置为一整天,但随后数据点会从其原始位置快速移动到粒度位置。
网格原点和间距的计算似乎是在 class AxisRenderer 的 computeAxisValues() 中完成的,但这class不能超载(?)
有没有办法在不改变库的情况下控制x轴标签的定位?
回答我自己的问题:
- 添加日期格式以及缩放常量:
private static final long MS_PER_XSCALE = 1000 * 60; // scale to minute resolution
private static final long XSCALE_ONE_DAY = 60 * 24; // one day
private final SimpleDateFormat xAxisDataFormat_DD_MMM_H = new SimpleDateFormat("dd.MMM'_'H'h'", Locale.ENGLISH);
private final SimpleDateFormat xAxisDataFormat_DD_MMM = new SimpleDateFormat("dd.MMM", Locale.ENGLISH);
private static final long TIMEOFFSET = TimeZone.getDefault().getRawOffset();
- 在 Activity: 的 onCreate() 中设置自定义日期轴渲染器和日期格式器
chart.setXAxisRenderer(new DateXAxisRenderer(chart.getViewPortHandler(), chart.getXAxis(), chart.getTransformer(null)));
chart.getXAxis().setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
if ((int) value / XSCALE_ONE_DAY * XSCALE_ONE_DAY == value)
return xAxisDataFormat_DD_MMM.format(new Date((long) value * MS_PER_XSCALE - TIMEOFFSET));
else
return xAxisDataFormat_DD_MMM_H.format(new Date((long) value * MS_PER_XSCALE - TIMEOFFSET));
}
});
- 按如下方式实现日期轴渲染器:
class DateXAxisRenderer extends XAxisRenderer {
public DateXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {
super(viewPortHandler, xAxis, trans);
}
@Override
protected void computeAxisValues(float min, float max) {
int day_fraction[] = {1,2,3,4,6,8,12,24};
float interval=0;
int labelCount=0;
float xMin = min;
float xMax = max;
xMax -= xMax % XSCALE_ONE_DAY;
xMin += XSCALE_ONE_DAY - (xMin % XSCALE_ONE_DAY);
int days = (int) ((xMax - xMin) / XSCALE_ONE_DAY);
float days_interval = days / 3;
if (days_interval > 0) {
interval = days_interval * XSCALE_ONE_DAY;
labelCount = (int) ((xMax - xMin) / interval);
}
if (days_interval == 0 || labelCount<3) {
int i = day_fraction.length-1;
do {
xMax = max - max % (XSCALE_ONE_DAY / day_fraction[i]);
xMin = min + (XSCALE_ONE_DAY / day_fraction[i] - (min % (XSCALE_ONE_DAY / day_fraction[i])));
labelCount = (int) ((xMax - xMin) / (XSCALE_ONE_DAY / day_fraction[i]));
} while (labelCount > 4 && i-- > 0);
interval = (xMax - xMin) / labelCount;
}
if (labelCount == 0 /*|| range <= 0 || Double.isInfinite(range)*/) {
mAxis.mEntries = new float[]{};
mAxis.mCenteredEntries = new float[]{};
mAxis.mEntryCount = 0;
return;
}
labelCount++; // add last label
//Timber.i("corrected min:" + xMin + ", max:" + xMax + ", interval:" + interval + ", labelcount:" + labelCount);
mAxis.mEntries = new float[labelCount];
float v = xMin;
for (int i = 0; i < labelCount; i++) {
mAxis.mEntries[i] = v;
Timber.i("Label " + i + " at:" + mAxis.mEntries[i] + " day:" + mAxis.mEntries[i] / XSCALE_ONE_DAY);
v += interval;
}
//mAxis.setLabelCount(labelCount);
//mAxis.setGranularityEnabled(false);
mAxis.mEntryCount = labelCount;
}
}
就是这样!
备注:很好地呈现的范围是天到分钟,但如果您需要年、月或秒,您必须相应地调整格式化程序以及已实现的 computeAxisValues()。