uni

University stuff
git clone git://git.margiolis.net/uni.git
Log | Files | Refs | README | LICENSE

Chart.java (5403B)


      1 package population;
      2 
      3 import java.util.ArrayList;
      4 import java.util.Collections;
      5 import java.util.Iterator;
      6 import java.util.List;
      7 import java.util.Map;
      8 import javafx.geometry.Insets;
      9 import javafx.geometry.Pos;
     10 import javafx.scene.Scene;
     11 import javafx.scene.chart.LineChart;
     12 import javafx.scene.chart.NumberAxis;
     13 import javafx.scene.chart.XYChart;
     14 import javafx.scene.control.Button;
     15 import javafx.scene.control.ComboBox;
     16 import javafx.scene.layout.HBox;
     17 import javafx.scene.layout.VBox;
     18 import javafx.stage.Modality;
     19 import javafx.stage.Stage;
     20 import javafx.stage.StageStyle;
     21 
     22 public class Chart {
     23 	private final int WIDTH = 1280;
     24 	private final int HEIGHT = 1000;
     25 	private final String TITLE = "Population Chart";
     26 	private Stage stg;
     27 	private VBox vb;
     28 	private HBox hb;
     29 	private Button btn_close;
     30 	private Button btn_clear;
     31 	private ComboBox<String> cb_ctry;
     32 	private ComboBox<Integer> cb_yearfrom;
     33 	private ComboBox<Integer> cb_yearto;
     34 	private NumberAxis xaxis;
     35 	private NumberAxis yaxis;
     36 	private LineChart<Number, Number> lc;
     37 	private ArrayList<XYChart.Series<Number, Number>> sr;
     38 	
     39 	Chart(List<Country> countries) {
     40 		sr = new ArrayList<XYChart.Series<Number, Number>>();
     41 		mkstage();
     42 		mkxaxis("Year");
     43 		mkyaxis("Population");
     44 		mklinechart();
     45 		mkclosebtn("Close");
     46 		mkclearbtn("Clear");
     47 		mkctrylist(countries, "Country");
     48 		cb_yearfrom = mkyearcb(Country.STARTING_YEAR);
     49 		cb_yearto = mkyearcb(Country.LAST_YEAR);
     50 		
     51 		/* Change timeline values. */
     52 		cb_yearfrom.setOnAction(ev -> {
     53 			if (cb_yearfrom.getValue() < cb_yearto.getValue())
     54 				xaxis.setLowerBound(cb_yearfrom.getValue());
     55 		});
     56 		cb_yearto.setOnAction(ev -> {
     57 			if (cb_yearto.getValue() > cb_yearfrom.getValue())
     58 				xaxis.setUpperBound(cb_yearto.getValue());
     59 		});
     60 	}
     61 	
     62 	private void mkstage() {
     63 		stg = new Stage();
     64 		stg.setWidth(WIDTH);
     65 		stg.setHeight(HEIGHT);
     66 		stg.initStyle(StageStyle.UTILITY);
     67 		stg.initModality(Modality.WINDOW_MODAL);
     68 	}
     69 	
     70 	private void mkxaxis(String str) {
     71 		xaxis = new NumberAxis();
     72 		xaxis.setLabel(str);
     73 		/* 
     74 		 * By default, the chart isn't resized properly
     75 		 * so we'll do it ourselves.
     76 		 */
     77 		xaxis.setLowerBound(Country.STARTING_YEAR);
     78 		xaxis.setUpperBound(Country.LAST_YEAR);
     79 		/* No. Stop auto resizing. */
     80 		xaxis.setAutoRanging(false);
     81 	}
     82 	
     83 	private void mkyaxis(String str) {
     84 		yaxis = new NumberAxis();
     85 		yaxis.setLabel(str);
     86 	}
     87 	
     88 	private void mklinechart() {
     89 		lc = new LineChart<Number, Number>(xaxis, yaxis);
     90 		
     91 		/* Fit to screen. */
     92 		lc.prefWidthProperty().bind(stg.widthProperty());
     93 		lc.prefHeightProperty().bind(stg.heightProperty());
     94 		
     95 		/* 
     96 		 * The animations look stupid when there's already another
     97 		 * chart present.
     98 		 */
     99 		lc.setAnimated(false);
    100 		
    101 		/* Do not draw nodes, just the line. */
    102 		lc.setCreateSymbols(false);
    103 	}
    104 	
    105 	private void mkclosebtn(String str) {
    106 		btn_close = new Button(str);
    107 		btn_close.setOnAction(ev -> {
    108 			stg.close();
    109 		});
    110 	}
    111 
    112 	private void mkclearbtn(String str) {
    113 		btn_clear = new Button(str);
    114 		btn_clear.setOnAction(ev -> {
    115 			lc.getData().clear();
    116 			sr.forEach(s -> s.getData().clear());
    117 			sr.clear();
    118 		});
    119 	}
    120 	
    121 	private ComboBox<Integer> mkyearcb(Integer n) {
    122 		ComboBox<Integer> cb = new ComboBox<Integer>();
    123 		for (int i = Country.STARTING_YEAR; i <= Country.LAST_YEAR; i++)
    124 			cb.getItems().add(i);
    125 		/* 
    126 		 * Set default values from the beginning, otherwise the 
    127 		 * very first action will not work properly as the value
    128 		 * in one of the ComboBoxes will be empty.
    129 		 */
    130 		cb.setValue(n);
    131 		return cb;
    132 	}
    133 	
    134 	private void mkctrylist(List<Country> countries, String str) {
    135 		cb_ctry = new ComboBox<String>();
    136 		countries.forEach(c -> cb_ctry.getItems().add(c.getName()));
    137 		cb_ctry.setPromptText(str);
    138 		/* 
    139 		 * Sort countries by name, since by default
    140 		 * each country is sorted by its index.
    141 		 */
    142 		Collections.sort(cb_ctry.getItems());
    143 		
    144 		/* Add population data for selected country to the chart. */
    145 		cb_ctry.setOnAction(ev -> {
    146 			Country c = null;
    147 			Iterator<Map.Entry<Integer, Integer>> it;
    148 			Map.Entry<Integer, Integer> ent;
    149 			String ctryname;
    150 			
    151 			/* Search country by selection name. */
    152 			ctryname = cb_ctry.getValue();
    153 			for (Country ctry : countries) {
    154 				if (ctry.getName().equals(ctryname)) {
    155 					c = ctry;
    156 					break;
    157 				}
    158 			}
    159 			/* Possibly a useless check. */
    160 			if (c == null)
    161 				return;
    162 			
    163 			sr.add(mkseries(c.getName()));
    164 			/* 
    165 			 * Iterate through the population data and make
    166 			 * the chart.
    167 			 */
    168 			it = c.getPopulation().entrySet().iterator();
    169 			while (it.hasNext()) {
    170 				ent = it.next();
    171 				sr.get(sr.size()-1).getData().add(
    172 				    new XYChart.Data<Number, Number>(
    173 				        ent.getKey(), ent.getValue()));
    174 			}
    175 			lc.getData().add(sr.get(sr.size()-1));
    176 		});
    177 	}
    178 	
    179 	private XYChart.Series<Number, Number> mkseries(String str) {
    180 		XYChart.Series<Number, Number> series;
    181 		
    182 		series = new XYChart.Series<Number, Number>();
    183 		series.setName(str);
    184 		return series;
    185 	}
    186 	
    187 	public void show() {
    188 		/* Create bottom panel. */
    189 		hb = new HBox();
    190 		hb.setSpacing(5);
    191 		hb.setAlignment(Pos.CENTER);
    192 		hb.getChildren().addAll(cb_yearfrom, cb_yearto,
    193 		    cb_ctry, btn_clear, btn_close);
    194 		/* 
    195 		 * Combine the chart and bottom panel, and display 
    196 		 * the scene. 
    197 		 */
    198 		vb = new VBox();
    199 		vb.setSpacing(5);
    200 		vb.setPadding(new Insets(10, 10, 10, 10));
    201 		vb.getChildren().addAll(lc, hb);
    202 		stg.setTitle(TITLE);
    203 		stg.setScene(new Scene(vb, 400, 200));
    204 		stg.show();
    205 	}
    206 }