From c027a0ee6e616c6b8051aeee02ee5cdb2f7d2788 Mon Sep 17 00:00:00 2001 From: Jessica McAuslin Date: Sun, 25 Jun 2017 19:59:59 +1200 Subject: [PATCH] Sparkline moved to its own class - Sparkline class creates and modifies sparkLine chart - removed sparkline implementation from RaceController - fixing RaceController code smells #story[876, 1003] --- .../seng302/Controllers/RaceController.java | 147 ++------------- .../main/java/seng302/Model/Sparkline.java | 174 ++++++++++++++++++ 2 files changed, 188 insertions(+), 133 deletions(-) create mode 100644 visualiser/src/main/java/seng302/Model/Sparkline.java diff --git a/visualiser/src/main/java/seng302/Controllers/RaceController.java b/visualiser/src/main/java/seng302/Controllers/RaceController.java index d36964a1..88915830 100644 --- a/visualiser/src/main/java/seng302/Controllers/RaceController.java +++ b/visualiser/src/main/java/seng302/Controllers/RaceController.java @@ -5,8 +5,6 @@ import javafx.application.Platform; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.chart.LineChart; -import javafx.scene.chart.NumberAxis; -import javafx.scene.chart.XYChart; import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; @@ -17,7 +15,10 @@ import seng302.Model.*; import seng302.VisualiserInput; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.ResourceBundle; /** * Created by fwy13 on 15/03/2017. @@ -47,16 +48,13 @@ public class RaceController extends Controller { private static int partialBtn = 3; private static int importantBtn = 4; - private ArrayList startBoats; - private Integer sparkLineNumber = 0; + private int legNum; + private Sparkline sparkline; private ResizableRaceCanvas raceMap; private ResizableRaceMap raceBoundaries; private ToggleGroup annotationGroup; - private ArrayList colours; - private Map boatColours = new HashMap<>(); - private int legNum; private RaceClock raceClock; @FXML Pane arrow; @@ -83,8 +81,6 @@ public class RaceController extends Controller { @FXML RadioButton partialAnnoRBTN; @FXML RadioButton importantAnnoRBTN; @FXML LineChart sparklineChart; - @FXML NumberAxis xAxis; - @FXML NumberAxis yAxis; /** * Updates the ResizableRaceCanvas (raceMap) with most recent data @@ -120,7 +116,6 @@ public class RaceController extends Controller { @Override public void initialize(URL location, ResourceBundle resources) { //listener for fps - startBoats = new ArrayList<>(); showFPS.selectedProperty().addListener((ov, old_val, new_val) -> { if (showFPS.isSelected()) { FPS.setVisible(true); @@ -138,60 +133,18 @@ public class RaceController extends Controller { /** * Creates and sets initial display for Sparkline for race positions. - * A data series for each boat in the race is added. - * Position numbers are displayed. - * * @param boats boats to display on the sparkline */ public void createSparkLine(ObservableList boats){ - // NOTE: Y axis is in negatives to display correct positions - - makeColours(); - startBoats.addAll(boats); - mapBoatColours(); - - // all boats start in 'last' place - for (int i=0; i series = new XYChart.Series(); - series.getData().add(new XYChart.Data(0, -startBoats.size())); - series.getData().add(new XYChart.Data(0, -startBoats.size())); - sparklineChart.getData().add(series); - sparklineChart.getData().get(i).getNode().setStyle("-fx-stroke: " + - ""+boatColours.get(startBoats.get(i).getSourceID())+";"); - } + sparkline = new Sparkline(boats, legNum, sparklineChart); + } - sparklineChart.setCreateSymbols(false); - - // set x axis details - xAxis.setAutoRanging(false); - xAxis.setTickMarkVisible(false); - xAxis.setTickLabelsVisible(false); - xAxis.setMinorTickVisible(false); - xAxis.setUpperBound((startBoats.size()+1)*legNum); - xAxis.setTickUnit((startBoats.size()+1)*legNum); - - - // set y axis details - yAxis.setLowerBound(-(startBoats.size()+1)); - yAxis.setUpperBound(0); - yAxis.setAutoRanging(false); - yAxis.setLabel("Position in Race"); - yAxis.setTickUnit(1); - yAxis.setTickMarkVisible(false); - yAxis.setMinorTickVisible(false); - // hide minus number from displaying on axis - yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) { - @Override - public String toString(Number value) { - if ((Double)value == 0.0 - || (Double)value < -startBoats.size()){ - return ""; - } - else { - return String.format("%7.0f", -value.doubleValue()); - } - } - }); + /** + * Updates the sparkline to display current boat positions. + * @param boatsInRace used for current boat positions. + */ + public void updateSparkline(ObservableList boatsInRace){ + sparkline.updateSparkline(boatsInRace); } /** @@ -282,78 +235,6 @@ public class RaceController extends Controller { }); } - /** - * Updates the sparkline to display current boat positions. - * New points are plotted to represent each boat when required. - * - * @param boatsInRace used for current boat positions. - */ - public void updateSparkline(ObservableList boatsInRace){ - int placingVal = boatsInRace.size(); - sparkLineNumber++; - - for (int i = boatsInRace.size() - 1; i >= 0; i--){ - for (int j = startBoats.size() - 1; j >= 0; j--){ - if (boatsInRace.get(i)==startBoats.get(j)){ - - // when a boat is on its first leg - if (boatsInRace.get(i).getCurrentLeg().getLegNumber()==0){ - // adjust boats latest point on X axis - sparklineChart.getData().get(j).getData().get(1) - .setXValue(sparkLineNumber); - } - - // when a boat first enters its second leg - else if (boatsInRace.get(i).getCurrentLeg().getLegNumber - ()==1 && sparklineChart.getData().get(j).getData - ().size()==2){ - // adjust boats position from start mark - sparklineChart.getData().get(j).getData().get(1) - .setYValue(-placingVal); - sparklineChart.getData().get(j).getData().get(1) - .setXValue(sparkLineNumber); - sparklineChart.getData().get(j).getData().add(new XYChart.Data<> - (sparkLineNumber, -placingVal)); - } - - // plot new point for boats current position - else { - sparklineChart.getData().get(j).getData().add - (new XYChart.Data<>(sparkLineNumber, -placingVal)); - } - placingVal-=1; - } - } - } -// xAxis.setUpperBound(sparkLineNumber); -// xAxis.setTickUnit(sparkLineNumber); - } - - private void makeColours() { - colours = new ArrayList<>(Arrays.asList( - colourToHex(Color.BLUEVIOLET), - colourToHex(Color.BLACK), - colourToHex(Color.RED), - colourToHex(Color.ORANGE), - colourToHex(Color.DARKOLIVEGREEN), - colourToHex(Color.LIMEGREEN), - colourToHex(Color.PURPLE), - colourToHex(Color.DARKGRAY), - colourToHex(Color.YELLOW) - )); - } - - private void mapBoatColours() { - int currentColour = 0; - for (Boat boat : startBoats) { - if (!boatColours.containsKey(boat.getSourceID())) { - boatColours.put(boat.getSourceID(), colours.get(currentColour)); - } - currentColour = (currentColour + 1) % colours.size(); - } - } - - private void storeCurrentAnnotationState(String dictionaryAnnotationKey, boolean selected){ if (buttonChecked != hideBtn) { //if we are checking the box straight out of hide instead of using the radio buttons diff --git a/visualiser/src/main/java/seng302/Model/Sparkline.java b/visualiser/src/main/java/seng302/Model/Sparkline.java new file mode 100644 index 00000000..a58815fc --- /dev/null +++ b/visualiser/src/main/java/seng302/Model/Sparkline.java @@ -0,0 +1,174 @@ +package seng302.Model; + +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.chart.LineChart; +import javafx.scene.chart.NumberAxis; +import javafx.scene.chart.XYChart; +import javafx.scene.paint.Color; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * Class to process and modify a sparkline display + */ +public class Sparkline { + private ArrayList colours; + private ArrayList startBoats = new ArrayList<>(); + private Map boatColours = new HashMap<>(); + private Integer legNum; + private Integer sparkLineNumber = 0; + @FXML LineChart sparklineChart; + @FXML NumberAxis xAxis; + @FXML NumberAxis yAxis; + + + /** + * Constructor to set up initial sparkline (LineChart) object + * @param boats boats to display on the sparkline + * @param legNum total number of legs in the race + * @param sparklineChart javaFX LineChart for the sparkline + */ + public Sparkline(ObservableList boats, Integer legNum, + LineChart sparklineChart) { + this.sparklineChart = sparklineChart; + this.legNum = legNum; + this.yAxis = (NumberAxis)sparklineChart.getYAxis(); + this.xAxis = (NumberAxis)sparklineChart.getXAxis(); + startBoats.addAll(boats); + + makeColours(); + mapBoatColours(); + createSparkline(); + } + + + /** + * Creates and sets initial display for Sparkline for race positions. + * A data series for each boat in the race is added. + * Position numbers are displayed. + */ + public void createSparkline(){ + // NOTE: Y axis is in negatives to display correct positions + + // all boats start in 'last' place + for (int i=0; i series = new XYChart.Series(); + series.getData().add(new XYChart.Data(0, -startBoats.size())); + series.getData().add(new XYChart.Data(0, -startBoats.size())); + sparklineChart.getData().add(series); + sparklineChart.getData().get(i).getNode().setStyle("-fx-stroke: " + + ""+boatColours.get(startBoats.get(i).getSourceID())+";"); + } + + sparklineChart.setCreateSymbols(false); + + // set x axis details + xAxis.setAutoRanging(false); + xAxis.setTickMarkVisible(false); + xAxis.setTickLabelsVisible(false); + xAxis.setMinorTickVisible(false); + xAxis.setUpperBound((startBoats.size()+1)*legNum); + xAxis.setTickUnit((startBoats.size()+1)*legNum); + + // set y axis details + yAxis.setLowerBound(-(startBoats.size()+1)); + yAxis.setUpperBound(0); + yAxis.setAutoRanging(false); + yAxis.setLabel("Position in Race"); + yAxis.setTickUnit(1); + yAxis.setTickMarkVisible(false); + yAxis.setMinorTickVisible(false); + + // hide minus number from displaying on axis + yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) { + @Override + public String toString(Number value) { + if ((Double)value == 0.0 + || (Double)value < -startBoats.size()){ + return ""; + } + else { + return String.format("%7.0f", -value.doubleValue()); + } + } + }); + } + + /** + * Updates the sparkline to display current boat positions. + * New points are plotted to represent each boat when required. + * @param boatsInRace current position of the boats in race + */ + public void updateSparkline(ObservableList boatsInRace){ + int placingVal = boatsInRace.size(); + sparkLineNumber++; + + for (int i = boatsInRace.size() - 1; i >= 0; i--){ + for (int j = startBoats.size() - 1; j >= 0; j--){ + if (boatsInRace.get(i)==startBoats.get(j)){ + + // when a boat is on its first leg + if (boatsInRace.get(i).getCurrentLeg().getLegNumber()==0){ + // adjust boats latest point on X axis + sparklineChart.getData().get(j).getData().get(1) + .setXValue(sparkLineNumber); + } + + // when a boat first enters its second leg + else if (boatsInRace.get(i).getCurrentLeg().getLegNumber + ()==1 && sparklineChart.getData().get(j).getData + ().size()==2){ + // adjust boats position from start mark + sparklineChart.getData().get(j).getData().get(1) + .setYValue(-placingVal); + sparklineChart.getData().get(j).getData().get(1) + .setXValue(sparkLineNumber); + sparklineChart.getData().get(j).getData().add(new XYChart.Data<> + (sparkLineNumber, -placingVal)); + } + + // plot new point for boats current position + else { + sparklineChart.getData().get(j).getData().add + (new XYChart.Data<>(sparkLineNumber, -placingVal)); + } + placingVal-=1; + } + } + } + } + + private void makeColours() { + colours = new ArrayList<>(Arrays.asList( + colourToHex(Color.BLUEVIOLET), + colourToHex(Color.BLACK), + colourToHex(Color.RED), + colourToHex(Color.ORANGE), + colourToHex(Color.DARKOLIVEGREEN), + colourToHex(Color.LIMEGREEN), + colourToHex(Color.PURPLE), + colourToHex(Color.DARKGRAY), + colourToHex(Color.YELLOW) + )); + } + + private String colourToHex(Color color) { + return String.format( "#%02X%02X%02X", + (int)( color.getRed() * 255 ), + (int)( color.getGreen() * 255 ), + (int)( color.getBlue() * 255 ) ); + } + + private void mapBoatColours() { + int currentColour = 0; + for (Boat boat : startBoats) { + if (!boatColours.containsKey(boat.getSourceID())) { + boatColours.put(boat.getSourceID(), colours.get(currentColour)); + } + currentColour = (currentColour + 1) % colours.size(); + } + } +}