package seng302.Controllers; 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.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.GridPane; import seng302.Mock.StreamedRace; import seng302.Model.*; import seng302.VisualiserInput; import java.awt.Color; import java.net.URL; import java.util.*; import java.util.List; /** * Created by fwy13 on 15/03/2017. */ public class RaceController extends Controller { @FXML GridPane canvasBase; //user saved data for annotation display private ArrayList presetAnno; private ArrayList startBoats; private Integer sparkLineNumber = 0; private ResizableRaceCanvas raceMap; private ResizableRaceMap raceBoundaries; private ArrayList colours; @FXML SplitPane race; @FXML CheckBox showFPS; @FXML CheckBox showBoatPath; @FXML CheckBox showAnnotations; @FXML Label timer; @FXML Label FPS; @FXML Label timeZone; @FXML CheckBox showName; @FXML CheckBox showAbbrev; @FXML CheckBox showSpeed; @FXML Button saveAnno; @FXML Button showSetAnno; @FXML TableView boatInfoTable; @FXML TableColumn boatPlacingColumn; @FXML TableColumn boatTeamColumn; @FXML TableColumn boatMarkColumn; @FXML TableColumn boatSpeedColumn; @FXML LineChart sparklineChart; @FXML NumberAxis xAxis; @FXML NumberAxis yAxis; /** * Updates the ResizableRaceCanvas (raceMap) with most recent data * * @param boats boats that are to be displayed in the race * @param boatMarkers Markers for boats * @see ResizableRaceCanvas */ public void updateMap(ObservableList boats, ObservableList boatMarkers) { raceMap.setBoats(boats); raceMap.setBoatMarkers(boatMarkers); raceMap.update(); raceBoundaries.draw(); //stop if the visualiser is no longer running } /** * Updates the array listened by the TableView (boatInfoTable) that displays the boat information. * * @param race Race to listen to. */ public void setInfoTable(StreamedRace race) { //boatInfoTable.getItems().clear(); ObservableList startingBoats = race.getStartingBoats(); boatInfoTable.setItems(race.getStartingBoats()); boatTeamColumn.setCellValueFactory(cellData -> cellData.getValue().getName()); boatSpeedColumn.setCellValueFactory(cellData -> cellData.getValue().getVelocityProp()); boatMarkColumn.setCellValueFactory(cellData -> cellData.getValue().getCurrentLegName()); boatPlacingColumn.setCellValueFactory(cellData -> cellData.getValue().positionProperty()); } @Override public void initialize(URL location, ResourceBundle resources) { //createSparkLine(); //listener for fps startBoats = new ArrayList<>(); showFPS.selectedProperty().addListener((ov, old_val, new_val) -> { if (showFPS.isSelected()) { FPS.setVisible(true); } else { FPS.setVisible(false); } }); } public void createSparkLine(ObservableList boats){ // TODO replace for loop with boatsInRace //int [] boats = {1, 2, 3, 4, 5, 6}; // set a line for each boat makeColours(); System.out.println(colours.get(0)); for (Boat boat : boats){ startBoats.add(boat); } for (int i=0; i series = new XYChart.Series(); series.getData().add(new XYChart.Data(0, i+1)); sparklineChart.getData().add(series); } // reverse Y axis order (0 at top) and set axis height/width // TODO change lower bound to boatsInRace + 1 yAxis.setLowerBound(startBoats.size()+1); yAxis.setUpperBound(0); yAxis.setAutoRanging(false); xAxis.setAutoRanging(false); sparklineChart.setCreateSymbols(false); sparklineChart.setStyle(".default-color0.chart-series-line { -fx-stroke: #e9967a; }"); // hide axis ticks and labels sparklineChart.getXAxis().setTickLabelsVisible(false); sparklineChart.getYAxis().setTickLabelsVisible(false); sparklineChart.getXAxis().setTickMarkVisible(false); sparklineChart.getYAxis().setTickMarkVisible(false); sparklineChart.getXAxis(). lookup(".axis-minor-tick-mark").setVisible(false); sparklineChart.getYAxis(). lookup(".axis-minor-tick-mark").setVisible(false); } /** * Initializes and runs the race, based on the user's chosen scale factor * Currently uses an example racecourse * * @param visualiserInput input from network * @param raceClock The RaceClock to use for the race's countdown/elapsed duration + timezone. */ public void startRace(VisualiserInput visualiserInput, RaceClock raceClock) { StreamedRace newRace = new StreamedRace(visualiserInput, this); //newRace.initialiseBoats(); raceMap = new ResizableRaceCanvas(visualiserInput.getCourse()); raceMap.setMouseTransparent(true); raceMap.widthProperty().bind(canvasBase.widthProperty()); raceMap.heightProperty().bind(canvasBase.heightProperty()); //raceMap.setBoats(newRace.getStartingBoats()); raceMap.draw(); raceMap.setVisible(true); canvasBase.getChildren().add(0, raceMap); raceBoundaries = new ResizableRaceMap(visualiserInput.getCourse()); raceBoundaries.setMouseTransparent(true); raceBoundaries.widthProperty().bind(canvasBase.widthProperty()); raceBoundaries.heightProperty().bind(canvasBase.heightProperty()); raceBoundaries.draw(); raceBoundaries.setVisible(true); canvasBase.getChildren().add(0, raceBoundaries); race.setVisible(true); //Initialize save annotation array, fps listener, and annotation listeners timeZone.setText(raceClock.getTimeZone()); timer.textProperty().bind(raceClock.durationProperty()); initializeFPS(); initializeAnnotations(); new Thread((newRace)).start(); } public void finishRace(ObservableList boats){ race.setVisible(false); parent.enterFinish(boats); } /** * Set the value for the race clock label * * @param time time that the label will be updated to */ public void setTimer(String time) { //timer.setText(time); } /** * Set the value for the fps label * * @param fps fps that the label will be updated to */ public void setFrames(String fps) { FPS.setText((fps)); } /** * Set up FPS display at bottom of screen */ private void initializeFPS() { showFPS.setVisible(true); showFPS.selectedProperty().addListener((ov, old_val, new_val) -> { if (showFPS.isSelected()) { FPS.setVisible(true); } else { FPS.setVisible(false); } }); } public void updateSparkline(ObservableList boatsInRace){ // TODO replace for loops with correct boats - Done //int [] startingBoats = {1, 2, 3, 4, 5, 6}; //int [] boatsInRace = {1, 2, 3, 4, 5, 6}; int colourIndex = 0; int placingVal = boatsInRace.size(); sparkLineNumber++; for (int i=0; i (sparkLineNumber, placingVal)); sparklineChart.getData().get(j).getNode().setStyle("-fx-stroke: "+colours.get(colourIndex)+";"); colourIndex+=1; placingVal-=1; } } } xAxis.setUpperBound(sparkLineNumber); } private void makeColours() { colours = new ArrayList<>(Arrays.asList( "#8A2BE2", "#000000", "#FF0000", "#FFA500", "#556B2F", "#32CD32", "#800080", "#A9A9A9", "#FFFF00" )); } /** * Set up boat annotations */ private void initializeAnnotations() { presetAnno = new ArrayList<>(); //listener for annotation showAnnotations.selectedProperty().addListener((ov, old_val, new_val) -> { raceMap.toggleAnnotations(); raceMap.update(); }); //listener for show name in annotation showName.selectedProperty().addListener((ov, old_val, new_val) -> { raceMap.toggleAnnoName(); raceMap.update(); }); //listener for show abbreviation for annotation showAbbrev.selectedProperty().addListener((ov, old_val, new_val) -> { raceMap.toggleAnnoAbbrev(); raceMap.update(); }); //listener for show boat path for annotation showBoatPath.selectedProperty().addListener((ov, old_val, new_val) -> { raceMap.toggleBoatPath(); raceMap.update(); }); //listener to show speed for annotation showSpeed.selectedProperty().addListener((ov, old_val, new_val) -> { raceMap.toggleAnnoSpeed(); raceMap.update(); }); //listener to save currently selected annotation saveAnno.setOnAction(event -> { presetAnno.clear(); presetAnno.add(showName.isSelected()); presetAnno.add(showAbbrev.isSelected()); presetAnno.add(showSpeed.isSelected()); presetAnno.add(showBoatPath.isSelected()); }); //listener to show saved annotation showSetAnno.setOnAction(event -> { if (presetAnno.size() > 0) { showName.setSelected(presetAnno.get(0)); showAbbrev.setSelected(presetAnno.get(1)); showSpeed.setSelected(presetAnno.get(2)); showBoatPath.setSelected(presetAnno.get(3)); raceMap.update(); } }); } }