是否有一种解决方法可以从一周的第一天开始制作DateAxis抽奖活动? [英] Is there a workaround to make DateAxis draw tick from the first day of the week?

查看:127
本文介绍了是否有一种解决方法可以从一周的第一天开始制作DateAxis抽奖活动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我创建一个需要带周周期的轴的图表时,我遇到了这个问题。

I bumped into this problem when I created a chart that need a axis with week period.

当我设置的刻度单位时DateAxis 使用 new DateTickUnit(DateTickUnitType.Day,7),它每7天显示一次刻度线。但是,刻度标记的日期不是从一周的第一天开始。您可以在屏幕截图中观察此行为。

When I set up tick unit of DateAxis with new DateTickUnit(DateTickUnitType.Day, 7), it display tick mark every 7 days. However, the date of tick mark does not start from the first day of the week. You can observer this behavior in the screenshot.

青色线 05-01 w18(5月1日,第18周)低于 w18(第18周)刻度线,这是因为刻度线 w18 的日期实际上是5月2日,也就是星期三。

Cyan color line 05-01 w18(May. 1, Week 18) is below the w18(Week 18) tick mark, this is because the date of tick mark w18 are actually May 2, which is Wednesday.

这个制作图表看起来不正确,因为人们倾向于认为每个刻度都是本周的开始。

This make chart looks incorrect because people tend to think each tick are suppose to be the start of the week.

检查源代码后,我发现 DateAxis 不支持周的这种行为(无论如何都没有周类型)。

After I check the source code, I found out that DateAxis dose not support such behavior for week (There is no week type anyway).

我无法创建另一个 DateTickUnitType ,因为私有构造函数和 correctTickDateForPosition() 中的方法DateAxis 也是私有的。我试图覆盖 nextStandardDate()但是没有满足结果。

I cannot to create another DateTickUnitType because the private constructor, and correctTickDateForPosition() method in DateAxis is also private. I have tried to override the nextStandardDate() but did not come out with satisfy result.

我该如何制作 DateAxis 总是从一周的第一天开始勾选刻度线?

How can I make DateAxis always draw tick mark start from first day of week ?

这是截图和示例代码

需要JFreeChart / JCommon

JFreeChart/JCommon required

public class Main extends ApplicationFrame {

  public Main (String title) throws ParseException {
    super(title);
    JPanel chartPanel = createDemoPanel();
    chartPanel.setPreferredSize(new java.awt.Dimension(800, 600));
    setContentPane(chartPanel);
  }

  private static JFreeChart createChart(XYDataset dataset) {
    JFreeChart chart = ChartFactory.createXYLineChart("Week period in DateAxis", "X", "Y", 
        dataset, PlotOrientation.VERTICAL, true, true, false);

    DateAxis x = new DateAxis("X");
    x.setTickUnit(new DateTickUnit(DateTickUnitType.MONTH, 1, new SimpleDateFormat("MMM.")));

    DateAxis y = new DateAxis("Y");
    y.setTickUnit(new DateTickUnit(DateTickUnitType.DAY, 7, new SimpleDateFormat("MM-dd 'W'w.")));

    XYPlot plot = chart.getXYPlot();
    plot.setDomainAxis(x);
    plot.setRangeAxis(y);
    plot.setDomainGridlinesVisible(true);
    plot.setRangeGridlinesVisible(true);
    XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
    renderer.setBaseShapesVisible(true);
    renderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator("{2}", 
        new SimpleDateFormat("MMM."), new SimpleDateFormat("MM-dd 'w'w")));
    renderer.setBaseItemLabelsVisible(true);
    return chart;
  }

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

    String[] allDate = new String[]{
        "2012/03/27", "2012/04/03", "2012/04/10", 
        "2012/04/17", "2012/04/24", "2012/05/01"};

    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 date : allDate) {
      XYSeries series = new XYSeries(date);

      series.add(df.parse(dateY1).getTime(), df.parse(date).getTime());
      series.add(df.parse(dateY2).getTime(), df.parse(date).getTime());
      series.add(df.parse(dateY3).getTime(), df.parse(date).getTime());
      series.add(df.parse(dateY4).getTime(), df.parse(date).getTime());
      series.add(df.parse(dateY5).getTime(), df.parse(date).getTime());
      series.add(df.parse(dateY6).getTime(), df.parse(date).getTime());
      dataset.addSeries(series);
    }
    return dataset;
  }

  public static JPanel createDemoPanel() throws ParseException {
    JFreeChart chart = createChart(createDataset());
    return new ChartPanel(chart);
  }

  public static void main(String[] args) throws ParseException {
    Main demo = new Main("Test");
    demo.pack();
    RefineryUtilities.centerFrameOnScreen(demo);
    demo.setVisible(true);
  }
}


推荐答案

这里是支持周期(仅限)的 DateAxis 的我的版本。

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);
  }
}



说明:



DateAxis 计算滴答时,它将从最低值开始,通过调用

Explanation :

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

nextStandardDate(getMinimumDate(), unit);

,其中 getMinimumDate()是边缘图表的价值。然后它将继续使用日期的最后一个滴答作为输入来计算下一个日期,直到它达到最高可用日期。

, 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.

所以我将时间设置为星期的第一天 previousStandardDate(),然后每当我计算下一个滴答时,我会在 previousStandardDate()的结果中添加一周。

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().

resetFieldBelowDay()部分只是删除一些噪音数据,这些数据可能会导致线条不与tick。

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 :

这篇关于是否有一种解决方法可以从一周的第一天开始制作DateAxis抽奖活动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆