MPAndroidChart:在日期格式上将网格和标签对齐到午夜 (00:00)

问题描述

问题:

MPAndroidChart 可以很好地计算十进制值的网格和标签位置,但不适用于日期/时间轴。

我希望标签位置正好是午夜,例如。 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-12h,28.1-00h]

我的尝试:

  1. 调整了 MPAndroidChart x-axis date/time label formatting解决方案,但它不适用于最近发布的 MPAndroidChart 3.1.0。

  2. 使用 setAxisMinimum()setAxisMaximum() 校正图表的最小值和最大值以修正午夜时间戳。

  3. 玩转不同的价值缩放。

  4. 使用 setGranularity() 将粒度设置为一整天,但随后数据点会从其原始位置快速移动到粒度位置。

网格原点和间距的计算似乎是在AxisRenderer类的computeAxisValues()中完成的,但是这个类不能重载(?)

有没有办法在不改变库的情况下控制x轴标签的定位?

解决方法

回答我自己的问题:

  1. 添加日期格式以及缩放常量:
    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();
  1. 在 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));
            }
        });
  1. 按如下方式实现日期轴渲染器:
 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()。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...