kauron/estraba
Archived
1
0
Fork 0

initial Dashboard distance -> time commit

This commit is contained in:
Jesús Vélez Palacios 2016-05-24 13:47:49 +02:00
parent 05d052fb00
commit b0433a32df
9 changed files with 157 additions and 66 deletions

View file

@ -58,11 +58,6 @@
<artifactId>controlsfx</artifactId> <artifactId>controlsfx</artifactId>
<version>8.40.10</version> <version>8.40.10</version>
</dependency> </dependency>
<dependency>
<groupId>jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.0.13</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.rterp</groupId> <groupId>com.github.rterp</groupId>
<artifactId>GMapsFX</artifactId> <artifactId>GMapsFX</artifactId>

View file

@ -61,6 +61,7 @@ public class App extends Application {
stage.setResizable(false); stage.setResizable(false);
stage.setScene(new Scene(root)); stage.setScene(new Scene(root));
if (getParameters().getUnnamed().size() == 1) { if (getParameters().getUnnamed().size() == 1) {
loader.<SplashController>getController().loadGPXFile(new File(getParameters().getUnnamed().get(0))); loader.<SplashController>getController().loadGPXFile(new File(getParameters().getUnnamed().get(0)));
} }

View file

@ -38,6 +38,7 @@ import javafx.collections.ObservableList;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.chart.AreaChart; import javafx.scene.chart.AreaChart;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
import javafx.scene.chart.PieChart; import javafx.scene.chart.PieChart;
@ -45,6 +46,7 @@ import javafx.scene.control.Label;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import jgpx.model.analysis.Chunk; import jgpx.model.analysis.Chunk;
@ -58,38 +60,40 @@ import java.util.ResourceBundle;
public class DashboardController implements Initializable, MapComponentInitializedListener { public class DashboardController implements Initializable, MapComponentInitializedListener {
final int N = 0, S = 1, E = 2, W = 3;
final double[] coord = new double[4];
@FXML @FXML
private AnchorPane root; private AnchorPane root;
@FXML @FXML
private Tab tabDashboard, tabMap, tabGraph, tabSettings; private Tab tabDashboard, tabMap, tabGraph, tabSettings;
@FXML @FXML
private ImageView imgHR, imgSpeed, imgCadence, imgDate, imgDistance, imgElevation; private ImageView imgHR, imgSpeed, imgCadence, imgDate, imgDistance, imgElevation;
@FXML @FXML
private Label valueHRAvg, valueHRMin, valueHRMax, valueSpeedAvg, valueSpeedMax, valueCadenceAvg, valueCadenceMax, private Label valueHRAvg, valueHRMin, valueHRMax, valueSpeedAvg, valueSpeedMax, valueCadenceAvg, valueCadenceMax,
valueDate, valueTime, valueActiveTime, valueTotalTime, valueDistance, valueElevation, labelMotivationUpper, valueDate, valueTime, valueActiveTime, valueTotalTime, valueDistance, valueElevation, labelMotivationUpper,
valueAscent, valueDescent, labelMotivatorLower; valueAscent, valueDescent, labelMotivatorLower;
@FXML @FXML
private JFXSpinner mapSpinner; private JFXSpinner mapSpinner;
@FXML @FXML
private PieChart zoneChart; private PieChart zoneChart;
@FXML @FXML
private GoogleMapView mapView; private GoogleMapView mapView;
private ObservableList<Chunk> chunks; private ObservableList<Chunk> chunks;
@FXML @FXML
private JFXButton elevationButton, speedButton, hrButton, cadenceButton; private JFXButton elevationButton, speedButton, hrButton, cadenceButton;
@FXML @FXML
private AreaChart<Double, Double> elevationChart; private AreaChart<Double, Double> elevationChart;
@FXML
private AreaChart<Long, Double> elevationTChart;
@FXML @FXML
private LineChart<Double, Double> speedChart, hrChart, cadenceChart, mapChart; private LineChart<Double, Double> speedChart, hrChart, cadenceChart, mapChart;
@FXML
private LineChart<Long, Double> speedTChart, hrTChart, cadenceTChart;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
// populate map icons // populate map icons
@ -105,6 +109,15 @@ public class DashboardController implements Initializable, MapComponentInitializ
imgDate.setImage(new Image(App.class.getResourceAsStream("img/date.png"))); imgDate.setImage(new Image(App.class.getResourceAsStream("img/date.png")));
imgDistance.setImage(new Image(App.class.getResourceAsStream("img/distance.png"))); imgDistance.setImage(new Image(App.class.getResourceAsStream("img/distance.png")));
imgElevation.setImage(new Image(App.class.getResourceAsStream("img/elevation.png"))); imgElevation.setImage(new Image(App.class.getResourceAsStream("img/elevation.png")));
}
@FXML
private void toggleChart(MouseEvent e) {
System.out.println("hi");
for (Node n : ((Node) e.getSource()).getParent().getChildrenUnmodifiable())
n.setVisible(!n.isVisible());
} }
@FXML @FXML
@ -149,9 +162,13 @@ public class DashboardController implements Initializable, MapComponentInitializ
// populate the charts // populate the charts
elevationChart.getData().add(bundle.elevationSeries); elevationChart.getData().add(bundle.elevationSeries);
elevationTChart.getData().add(bundle.elevationTSeries);
speedChart.getData().add(bundle.speedSeries); speedChart.getData().add(bundle.speedSeries);
speedTChart.getData().add(bundle.speedTSeries);
hrChart.getData().add(bundle.hrSeries); hrChart.getData().add(bundle.hrSeries);
hrTChart.getData().add(bundle.hrTSeries);
cadenceChart.getData().add(bundle.cadenceSeries); cadenceChart.getData().add(bundle.cadenceSeries);
cadenceTChart.getData().add(bundle.cadenceTSeries);
//initialize map //initialize map
chunks = bundle.chunks; chunks = bundle.chunks;
@ -161,8 +178,6 @@ public class DashboardController implements Initializable, MapComponentInitializ
@Override @Override
public void mapInitialized() { public void mapInitialized() {
// When the JS init is done // When the JS init is done
final int N = 0, S = 1, E = 2, W = 3;
final double[] coord = new double[4];
coord[0] = Double.MIN_VALUE; coord[0] = Double.MIN_VALUE;
coord[1] = Double.MAX_VALUE; coord[1] = Double.MAX_VALUE;
coord[2] = Double.MIN_VALUE; coord[2] = Double.MIN_VALUE;
@ -212,13 +227,20 @@ public class DashboardController implements Initializable, MapComponentInitializ
chunks.get(chunks.size() - 1).getLastPoint().getLongitude())) chunks.get(chunks.size() - 1).getLastPoint().getLongitude()))
.title("label.end"))); .title("label.end")));
// Adjust the map to the correct center and zoom // Adjust the map to the correct center and zoom
map.fitBounds(new LatLongBounds( mapView.setVisible(true);
mapSpinner.setVisible(false);
mapView.heightProperty().addListener(e -> centerMap());
mapView.widthProperty().addListener(e -> centerMap());
centerMap();
}
private void centerMap() {
mapView.getMap().setZoom(getBoundsZoomLevel(coord, mapView.getHeight(), mapView.getWidth()));
mapView.getMap().fitBounds(new LatLongBounds(
new LatLong(coord[S], coord[W]), new LatLong(coord[S], coord[W]),
new LatLong(coord[N], coord[E]) new LatLong(coord[N], coord[E])
)); ));
map.setZoom(getBoundsZoomLevel(coord, mapView.getHeight(), mapView.getWidth()));
mapView.setVisible(true);
mapSpinner.setVisible(false);
} }
/** /**

View file

@ -30,7 +30,6 @@ import com.jfoenix.controls.JFXSnackbar;
import com.jfoenix.controls.JFXSpinner; import com.jfoenix.controls.JFXSpinner;
import es.kauron.estraba.App; import es.kauron.estraba.App;
import es.kauron.estraba.model.DataBundle; import es.kauron.estraba.model.DataBundle;
import javafx.application.Platform;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -100,8 +99,14 @@ public class SplashController implements Initializable{
snackbar.show("Loading file", 5000); snackbar.show("Loading file", 5000);
Thread th = new Thread(new Task<DataBundle>() { Thread th = new Thread(new Task<DataBundle>() {
@Override @Override
protected DataBundle call() throws Exception { protected DataBundle call() {
return DataBundle.loadFrom(file); DataBundle db = null;
try {
db = DataBundle.loadFrom(file);
} catch (Exception e) {
e.printStackTrace();
}
return db;
} }
@Override @Override
@ -117,6 +122,7 @@ public class SplashController implements Initializable{
loader.<DashboardController>getController().load(bundle); loader.<DashboardController>getController().load(bundle);
((Stage) root.getScene().getWindow()).setScene(new Scene(parent)); ((Stage) root.getScene().getWindow()).setScene(new Scene(parent));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace();
errorLoading(); errorLoading();
} }
} }
@ -145,37 +151,33 @@ public class SplashController implements Initializable{
} }
}); });
Platform.runLater(() -> root.getScene().setOnDragOver(e -> { root.setOnDragOver(e -> {
Dragboard db = e.getDragboard(); Dragboard db = e.getDragboard();
if (db.hasFiles()) { if (db.hasFiles()) {
e.acceptTransferModes(TransferMode.COPY); e.acceptTransferModes(TransferMode.COPY);
} else { } else {
e.consume(); e.consume();
} }
})); });
// Dropping over surface // Dropping over surface
Platform.runLater(() -> root.getScene().setOnDragDropped(e -> { root.setOnDragDropped(e -> {
Dragboard db = e.getDragboard(); Dragboard db = e.getDragboard();
boolean success = false; boolean success = false;
if (db.hasFiles()) { if (db.hasFiles()) {
success = true; success = true;
String filePath = null; loadGPXFile(db.getFiles().get(0).getAbsoluteFile());
for (File file : db.getFiles()) {
filePath = file.getAbsolutePath();
System.out.println(filePath);
}
} }
e.setDropCompleted(success); e.setDropCompleted(success);
e.consume(); e.consume();
})); });
} }
private void errorLoading() { private void errorLoading() {
buttonLoad.setVisible(true); buttonLoad.setVisible(true);
labelWelcome.setVisible(true); labelWelcome.setVisible(true);
spinner.setVisible(false); spinner.setVisible(false);
snackbar.show("Error loading file", 3000); snackbar.show(App.GENERAL_BUNDLE.getString("error.file"), 3000);
} }
} }

View file

@ -40,23 +40,24 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller; import javax.xml.bind.Unmarshaller;
import java.io.File; import java.io.File;
import java.time.Duration;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle; import java.time.format.FormatStyle;
public class DataBundle { public class DataBundle {
public static final int N = 0, S = 1, E = 2, W = 3;
private static final double DISTANCE_EPSILON = 1E-6; private static final double DISTANCE_EPSILON = 1E-6;
private static final double KILOMETER_CUTOFF = 10000; private static final double KILOMETER_CUTOFF = 10000;
public String HRAvg, HRMax, HRMin, speedAvg, speedMax, cadenceAvg, cadenceMax; public String HRAvg, HRMax, HRMin, speedAvg, speedMax, cadenceAvg, cadenceMax;
public String date, time, activeTime, totalTime, distance, elevation, ascent, descent; public String date, time, activeTime, totalTime, distance, elevation, ascent, descent;
public XYChart.Series<Double, Double> elevationSeries, speedSeries, hrSeries, cadenceSeries; public XYChart.Series<Double, Double> elevationSeries, speedSeries, hrSeries, cadenceSeries;
public XYChart.Series<Long, Double> elevationTSeries, speedTSeries, hrTSeries, cadenceTSeries;
public ObservableList<PieChart.Data> pieData; public ObservableList<PieChart.Data> pieData;
public ObservableList<Chunk> chunks; public ObservableList<Chunk> chunks;
private DataBundle(TrackData track) { private DataBundle(TrackData track) {
HRAvg = track.getAverageHeartrate() + App.GENERAL_BUNDLE.getString("unit.bpm"); HRAvg = track.getAverageHeartrate() + App.GENERAL_BUNDLE.getString("unit.bpm");
HRMax = track.getMaxHeartrate() + App.GENERAL_BUNDLE.getString("unit.bpm"); HRMax = track.getMaxHeartrate() + App.GENERAL_BUNDLE.getString("unit.bpm");
HRMin = track.getMinHeartRate() + App.GENERAL_BUNDLE.getString("unit.bpm"); HRMin = track.getMinHeartRate() + App.GENERAL_BUNDLE.getString("unit.bpm");
@ -87,23 +88,34 @@ public class DataBundle {
// traverse the chunks // traverse the chunks
chunks = track.getChunks(); chunks = track.getChunks();
double currentDistance = 0.0; double currentDistance = 0.0;
Duration currentTime = Duration.ZERO;
double currentHeight = chunks.get(0).getFirstPoint().getElevation(); double currentHeight = chunks.get(0).getFirstPoint().getElevation();
elevationSeries = new XYChart.Series<>(); elevationSeries = new XYChart.Series<>();
elevationTSeries = new XYChart.Series<>();
cadenceSeries = new XYChart.Series<>(); cadenceSeries = new XYChart.Series<>();
cadenceTSeries = new XYChart.Series<>();
hrSeries = new XYChart.Series<>(); hrSeries = new XYChart.Series<>();
hrTSeries = new XYChart.Series<>();
speedSeries = new XYChart.Series<>(); speedSeries = new XYChart.Series<>();
speedTSeries = new XYChart.Series<>();
pieData = FXCollections.observableArrayList(); pieData = FXCollections.observableArrayList();
for (Chunk chunk : chunks) { for (Chunk chunk : chunks) {
currentDistance += chunk.getDistance(); currentDistance += chunk.getDistance();
if (chunk.getDistance() < DISTANCE_EPSILON) continue; currentTime = currentTime.plus(chunk.getMovingTime());
if (chunk.getDistance() < DISTANCE_EPSILON ||
chunk.getMovingTime().getSeconds() < 1) continue;
currentHeight += chunk.getAscent() - chunk.getDescend(); currentHeight += chunk.getAscent() - chunk.getDescend();
elevationSeries.getData().add(new XYChart.Data<>(currentDistance, currentHeight)); elevationSeries.getData().add(new XYChart.Data<>(currentDistance, currentHeight));
elevationTSeries.getData().add(new XYChart.Data<>(currentTime.toMinutes(), currentHeight));
speedSeries.getData().add(new XYChart.Data<>(currentDistance, chunk.getSpeed()*3.6)); // m/s speedSeries.getData().add(new XYChart.Data<>(currentDistance, chunk.getSpeed()*3.6)); // m/s
speedTSeries.getData().add(new XYChart.Data<>(currentTime.toMinutes(), chunk.getSpeed() * 3.6)); // m/s
hrSeries.getData().add(new XYChart.Data<>(currentDistance, chunk.getAvgHeartRate())); hrSeries.getData().add(new XYChart.Data<>(currentDistance, chunk.getAvgHeartRate()));
hrTSeries.getData().add(new XYChart.Data<>(currentTime.toMinutes(), chunk.getAvgHeartRate()));
cadenceSeries.getData().add(new XYChart.Data<>(currentDistance, chunk.getAvgCadence())); cadenceSeries.getData().add(new XYChart.Data<>(currentDistance, chunk.getAvgCadence()));
cadenceTSeries.getData().add(new XYChart.Data<>(currentTime.toMinutes(), chunk.getAvgCadence()));
String zone; String zone;
if (chunk.getAvgHeartRate() > 170) zone = App.GENERAL_BUNDLE.getString("zone.anaerobic"); if (chunk.getAvgHeartRate() > 170) zone = App.GENERAL_BUNDLE.getString("zone.anaerobic");

View file

@ -365,7 +365,7 @@
<padding> <padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding> </padding>
<StackPane prefHeight="150.0" prefWidth="200.0" VBox.vgrow="ALWAYS" > <StackPane prefHeight="150.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
<children> <children>
<GoogleMapView fx:id="mapView" /> <GoogleMapView fx:id="mapView" />
<JFXSpinner fx:id="mapSpinner" /> <JFXSpinner fx:id="mapSpinner" />
@ -422,38 +422,94 @@
<padding> <padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding> </padding>
<AreaChart fx:id="elevationChart" createSymbols="false" legendVisible="false" minHeight="100.0"> <StackPane>
<xAxis> <children>
<NumberAxis side="BOTTOM" /> <AreaChart fx:id="elevationChart" createSymbols="false" legendVisible="false" minHeight="100.0"
</xAxis> onMouseClicked="#toggleChart">
<yAxis> <xAxis>
<NumberAxis side="LEFT" /> <NumberAxis side="BOTTOM"/>
</yAxis> </xAxis>
</AreaChart> <yAxis>
<LineChart fx:id="speedChart" createSymbols="false" legendVisible="false" minHeight="100.0"> <NumberAxis side="LEFT"/>
<xAxis> </yAxis>
<NumberAxis /> </AreaChart>
</xAxis> <AreaChart fx:id="elevationTChart" createSymbols="false" layoutX="10.0" layoutY="10.0"
<yAxis> legendVisible="false" minHeight="100.0" onMouseClicked="#toggleChart" visible="false">
<NumberAxis side="LEFT" /> <xAxis>
</yAxis> <NumberAxis/>
</LineChart> </xAxis>
<LineChart fx:id="hrChart" createSymbols="false" legendVisible="false" minHeight="100.0"> <yAxis>
<xAxis> <NumberAxis side="LEFT"/>
<NumberAxis side="BOTTOM" /> </yAxis>
</xAxis> </AreaChart>
<yAxis> </children>
<NumberAxis side="LEFT" /> </StackPane>
</yAxis> <StackPane>
</LineChart> <children>
<LineChart fx:id="cadenceChart" createSymbols="false" legendVisible="false" minHeight="100.0"> <LineChart fx:id="speedChart" createSymbols="false" legendVisible="false" minHeight="100.0"
<xAxis> onMouseClicked="#toggleChart">
<NumberAxis side="BOTTOM" /> <xAxis>
</xAxis> <NumberAxis/>
<yAxis> </xAxis>
<NumberAxis side="LEFT" /> <yAxis>
</yAxis> <NumberAxis side="LEFT"/>
</LineChart> </yAxis>
</LineChart>
<LineChart fx:id="speedTChart" createSymbols="false" layoutX="10.0" layoutY="10.0"
legendVisible="false" minHeight="100.0" onMouseClicked="#toggleChart" visible="false">
<xAxis>
<NumberAxis/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</LineChart>
</children>
</StackPane>
<StackPane>
<children>
<LineChart fx:id="hrChart" createSymbols="false" legendVisible="false" minHeight="100.0"
onMouseClicked="#toggleChart">
<xAxis>
<NumberAxis side="BOTTOM"/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</LineChart>
<LineChart fx:id="hrTChart" createSymbols="false" layoutX="10.0" layoutY="10.0" legendVisible="false"
minHeight="100.0" onMouseClicked="#toggleChart" visible="false">
<xAxis>
<NumberAxis/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</LineChart>
</children>
</StackPane>
<StackPane>
<children>
<LineChart fx:id="cadenceChart" createSymbols="false" legendVisible="false" minHeight="100.0"
onMouseClicked="#toggleChart">
<xAxis>
<NumberAxis side="BOTTOM"/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</LineChart>
<LineChart fx:id="cadenceTChart" createSymbols="false" layoutX="10.0" layoutY="10.0"
legendVisible="false" minHeight="100.0" onMouseClicked="#toggleChart" visible="false">
<xAxis>
<NumberAxis/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</LineChart>
</children>
</StackPane>
</VBox> </VBox>
</Tab> </Tab>
<Tab fx:id="tabSettings" text="%tab.settings"> <Tab fx:id="tabSettings" text="%tab.settings">

View file

@ -25,6 +25,7 @@
app.extension=GPX data files app.extension=GPX data files
app.title=ESTRABA app.title=ESTRABA
error.file=Error loading file
label.begin=Salida label.begin=Salida
label.cadence=Cadence label.cadence=Cadence
label.distance=Distance label.distance=Distance

View file

@ -25,6 +25,7 @@
app.extension=Arxius GPX app.extension=Arxius GPX
app.title=ESTRABA app.title=ESTRABA
error.file=Error
label.begin=Salida label.begin=Salida
label.cadence=Cadencia label.cadence=Cadencia
label.distance=Distancia label.distance=Distancia

View file

@ -25,6 +25,7 @@
app.extension=Archivos de datos GPX app.extension=Archivos de datos GPX
app.title=ESTRABA app.title=ESTRABA
error.file=Error al cargar el archivo
label.begin=Salida label.begin=Salida
label.cadence=Cadencia label.cadence=Cadencia
label.distance=Distancia label.distance=Distancia