Is there a workaround to make DateAxis draw tick from the first day of the week?

放肆的年华 提交于 2019-12-06 09:55:43

Here is the my version of the DateAxis that supported week period (only).

public static class WeeklyDateAxis extends DateAxis {

  private static final long serialVersionUID = 1L;
  private Locale locale;

  public WeeklyDateAxis(String label, TimeZone zone, Locale locale) {
    super(label, zone, locale);
    this.locale = locale;
  }

  @Override
  protected Date previousStandardDate(Date date, DateTickUnit unit) {
    Calendar cal = Calendar.getInstance(getTimeZone(), locale);
    cal.setTime(date);
    resetFieldBelowDay(cal);

    cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
    return cal.getTime();
  }

  @Override
  protected Date nextStandardDate(Date date, DateTickUnit unit) {
    Date previous = previousStandardDate(date, unit);
    Calendar cal = Calendar.getInstance(getTimeZone(), locale);
    cal.setTime(previous);
    resetFieldBelowDay(cal);

    cal.add(Calendar.WEEK_OF_YEAR, 1);
    return cal.getTime();
  }

  private void resetFieldBelowDay(Calendar cal) {
    cal.clear(Calendar.MILLISECOND);
    cal.clear(Calendar.SECOND);
    cal.clear(Calendar.MINUTE);
    cal.set(Calendar.HOUR_OF_DAY, 0);
  }
}

Explanation :

When DateAxis calculate ticks, it will start from the lowest value by calling

nextStandardDate(getMinimumDate(), unit);

, where getMinimumDate() are the edge value of the chart. Then it will keep using the last tick of date as input to calculate next date until it reach the highest available date.

So I set the time to first day of week in previousStandardDate(), then every time I calculate the next tick, I add one week to result of the previousStandardDate().

The resetFieldBelowDay() part are simply to remove some noise data that can cause line dose not align with the tick.

Here is another data set I use to validate the result, you can simply replace the it with the example code I provide in question.

private static XYDataset createDataset() throws ParseException {
  SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");

  String[][] allDate = new String[][] {
      {"2012/03/25", "2012/03/29", "2012/03/28", "2012/03/27", "2012/03/27", "2012/03/27"},
      {"2012/04/01", "2012/04/02", "2012/04/06", "2012/04/06", "2012/04/06", "2012/04/06"},
      {"2012/04/11", "2012/04/12", "2012/04/08", "2012/04/10", "2012/04/10", "2012/04/10"},
      {"2012/04/15", "2012/04/14", "2012/04/15", "2012/04/18", "2012/04/19", "2012/04/19"},
      {"2012/05/01", "2012/05/02", "2012/05/08", "2012/05/04", "2012/05/04", "2012/05/04"},
      {"2012/05/12", "2012/05/12", "2012/05/18", "2012/05/14", "2012/05/14", "2012/05/14"},
      {"2012/05/22", "2012/05/22", "2012/05/28", "2012/05/28", "2012/05/28", "2012/05/30"},
  };

  String dateY1 = "2012/01/15";
  String dateY2 = "2012/02/15";
  String dateY3 = "2012/03/15";
  String dateY4 = "2012/04/15";
  String dateY5 = "2012/05/15";
  String dateY6 = "2012/06/15";

  XYSeriesCollection dataset = new XYSeriesCollection();
  for (String[] dateOfOneSeries : allDate) {
    XYSeries series = new XYSeries(dateOfOneSeries[0]);

    series.add(df.parse(dateY1).getTime(), df.parse(dateOfOneSeries[0]).getTime());
    series.add(df.parse(dateY2).getTime(), df.parse(dateOfOneSeries[1]).getTime());
    series.add(df.parse(dateY3).getTime(), df.parse(dateOfOneSeries[2]).getTime());
    series.add(df.parse(dateY4).getTime(), df.parse(dateOfOneSeries[3]).getTime());
    series.add(df.parse(dateY5).getTime(), df.parse(dateOfOneSeries[4]).getTime());
    series.add(df.parse(dateY6).getTime(), df.parse(dateOfOneSeries[5]).getTime());
    dataset.addSeries(series);
  }
  return dataset;
}

Result :

By overriding previousStandardDate of DateAxis I managed to adjust the day of the week for the tick marks.

In your example the data is displayed for Tuesdays, so in the code below the first day of week for Calendar is set to Tuesday, which aligns the data lines with the tick marks.

DateAxis y = new DateAxis("Y") {
  @Override
  protected Date previousStandardDate(Date date, DateTickUnit unit) {
    Date prevDate = super.previousStandardDate(date, unit);

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(prevDate);

    int showDayOfWeek = Calendar.TUESDAY;
    calendar.setFirstDayOfWeek(showDayOfWeek);
    if (showDayOfWeek != calendar.get(Calendar.DAY_OF_WEEK)) {
      calendar.set(Calendar.DAY_OF_WEEK, showDayOfWeek);
    }

    return calendar.getTime();
  }
};

[Edit:] I just realized that you don't actually want to align the tick marks, but show them at the actual first day of the week. The solution for that would be

DateAxis y = new DateAxis("Y") {    
  @Override
  protected Date previousStandardDate(Date date, DateTickUnit unit) {
    Date prevDate = super.previousStandardDate(date, unit);

    Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
    calendar.setTime(prevDate);

    int firstDayOfWeek = calendar.getFirstDayOfWeek();
    if (firstDayOfWeek != calendar.get(Calendar.DAY_OF_WEEK)) {
      calendar.set(Calendar.DAY_OF_WEEK, firstDayOfWeek);
    }

    return calendar.getTime();
  }
};
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!