When trying to build an application which contains an updateable LineChart
or AreaChart
I recognized strange behaviour - probably due to an error in application logic?
The goal is to fill data into or update a chart when a button "Generate" is clicked. User has to input a start time and an end time for the graph, in addition an interval Hours / Days / Weeks has to be chosen (by using a RadioGroup
).
Creation of the initial chart works without any problems. Re-generating the chart works properly too, but only as long as data points didn't exist in previous chart. If data points with same x-values are contained in both charts (old and updated one), sorting isn't ascending anymore.
Example:
Execution with StartDate: 01.09.2013 EndDate: 25.09.2013 Interval: Weeks
Values on x-axis:
01.09.2013 / 08.09.2013 / 15.09.2013 / 22.09.2013
Clicking the "Days" RadioButton
an re-generating the chart yields to following values on x-axis:
01.09.2013 / 08.09.2013 / 15.09.2013 / 22.09.2013 / 02.09.2013 / 03.09.2013 / 04.09.2013 / ...
(values should be 01.09.2013 / 02.09.2013 / 03.09.2013 / ...)
All values which already have been shown in first chart and are in second chart too, are sorted at the beginning of the new chart (and not in ascending order)
Here's the code that does the trick (code for method initializeTimeline
is just for testing purposes (surely a bit optimizable ;))):
public class ChartDesignController implements Initializable {
@FXML
private AreaChart chartOne;
@FXML
private TextField startDate;
@FXML
private TextField endDate;
@FXML
private RadioButton radioHours;
@FXML
private RadioButton radioDays;
@FXML
private RadioButton radioWeeks;
@FXML
private ToggleGroup timeUnit;
@FXML
private Label msgBox;
@FXML
private void generateGraph(ActionEvent event) {
String timeUnit = getTimeUnit();
Series s = initializeTimeline(startDate.getText(), endDate.getText(), timeUnit);
chartOne.getData().setAll(s);
}
private String getTimeUnit() {
String timeUnitForQuery = "DD";
RadioButton selectedRadio = (RadioButton) timeUnit.getSelectedToggle();
if (selectedRadio == radioHours) {
//System.out.println("RadioHours was selected");
timeUnitForQuery = "HH24";
}
if (selectedRadio == radioDays) {
//System.out.println("RadioDays was selected");
timeUnitForQuery = "DD";
}
if (selectedRadio == radioWeeks) {
//System.out.println("RadioWeeks was selected");
timeUnitForQuery = "IW";
}
//System.out.println("Time unit changed");
return timeUnitForQuery;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
}
private Series initializeTimeline(String startTime, String endTime, String timeUnit) {
msgBox.setText("");
long delta;
int nrOfTicks = 0;
Data<String, Integer> dp;
Series s = new Series();
ArrayList<Data<String, Integer>> dataPoints = new ArrayList();
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
Date startDate = new Date();
Date endDate = new Date();
GregorianCalendar startTimeGC = new GregorianCalendar();
GregorianCalendar endTimeGC = new GregorianCalendar();
if (timeUnit.equalsIgnoreCase("HH24")) {
sdf = new SimpleDateFormat("dd.MM.yyyy HH");
}
try {
startDate = sdf.parse(startTime);
endDate = sdf.parse(endTime);
} catch (ParseException ex) {
msgBox.setText(ex.getMessage() + "\n" + "Format expected: " + sdf.toPattern());
}
startTimeGC.setTimeInMillis(startDate.getTime());
endTimeGC.setTimeInMillis(endDate.getTime());
delta = endTimeGC.getTimeInMillis() - startTimeGC.getTimeInMillis();
if (timeUnit.equalsIgnoreCase("HH24")) {
nrOfTicks = (int) (delta / 1000 / 60 / 60) + 1;
} else if (timeUnit.equalsIgnoreCase("DD")) {
nrOfTicks = (int) (delta / 1000 / 60 / 60 / 24) + 1;
} else if (timeUnit.equalsIgnoreCase("IW")) {
nrOfTicks = (int) (delta / 1000 / 60 / 60 / 24 / 7) + 1;
}
for (int i = 0; i < nrOfTicks; i++) {
dp = new Data(sdf.format(startTimeGC.getTime()), 0);
dataPoints.add(dp);
if (timeUnit.equalsIgnoreCase("HH24")) {
startTimeGC.add(GregorianCalendar.HOUR_OF_DAY, 1);
} else if (timeUnit.equalsIgnoreCase("DD")) {
startTimeGC.add(GregorianCalendar.DAY_OF_MONTH, 1);
} else if (timeUnit.equalsIgnoreCase("IW")) {
startTimeGC.add(GregorianCalendar.WEEK_OF_YEAR, 1);;
}
}
dataPoints.sort(new DataComparator());
s.setData(FXCollections.observableList(dataPoints));
return s;
}
}
Below, the DataComparator
which is in charge of sorting the dataPoints
alphabetically according to their x-values:
public class DataComparator implements Comparator<Data> {
@Override
public int compare(Data d1, Data d2) {
String d1Xval = (String) d1.getXValue();
String d2Xval = (String) d2.getXValue();
return d1Xval.compareTo(d2Xval);
}
}
When debugging the program values are sorted correctly in ArrayList
dataPoints
.
Any ideas why values are sorted incorrectly then in chart x-axis, in case they already appeared in old chart?
Would greatly appreciate help for this "issue".