Commit f39d90e6068c17e06645704f2f102d47aa985a59
1 parent
f15a589072
Exists in
master
and in
1 other branch
Select/deselect MMSI
Showing 14 changed files with 76 additions and 120 deletions Side-by-side Diff
- src/main/kotlin/application/App.kt
- src/main/kotlin/application/Logger.kt
- src/main/kotlin/application/VisualisationChart.kt
- src/main/kotlin/application/controller/DataPanelController.kt
- src/main/kotlin/application/controller/MapPanelController.kt
- src/main/kotlin/application/controller/VesselListPanelController.kt
- src/main/kotlin/application/model/Message.kt
- src/main/kotlin/application/model/MessageData.kt
- src/main/kotlin/application/model/MessageListener.kt
- src/main/kotlin/application/model/ObservableVessel.kt
- src/main/kotlin/application/model/Vessel.kt
- src/main/kotlin/application/model/VesselGenerator.kt
- src/main/kotlin/map/MapDisplayer.kt
- src/main/resources/gui/vesselListPanel.fxml
src/main/kotlin/application/App.kt
View file @
f39d90e
1 | +@file:JvmName("App") | |
2 | + | |
1 | 3 | package application |
2 | 4 | |
3 | 5 | import javafx.application.Application |
4 | 6 | |
... | ... | @@ -7,13 +9,12 @@ |
7 | 9 | import javafx.scene.Parent |
8 | 10 | import javafx.scene.Scene |
9 | 11 | import javafx.stage.Stage |
10 | -import javafx.stage.WindowEvent | |
11 | 12 | import jfxtras.styles.jmetro.JMetro |
12 | 13 | import jfxtras.styles.jmetro.Style |
13 | 14 | import kotlin.system.exitProcess |
14 | 15 | |
15 | 16 | class App : Application() { |
16 | - var style : Style = Style.LIGHT | |
17 | + var style: Style = Style.LIGHT | |
17 | 18 | |
18 | 19 | override fun start(primaryStage: Stage?) { |
19 | 20 |
src/main/kotlin/application/Logger.kt
View file @
f39d90e
src/main/kotlin/application/VisualisationChart.kt
View file @
f39d90e
src/main/kotlin/application/controller/DataPanelController.kt
View file @
f39d90e
... | ... | @@ -7,14 +7,11 @@ |
7 | 7 | import javafx.fxml.Initializable |
8 | 8 | import javafx.scene.control.ListCell |
9 | 9 | import javafx.scene.control.ListView |
10 | -import javafx.scene.layout.StackPane | |
11 | 10 | import org.charts.dataviewer.api.config.DataViewerConfiguration |
12 | 11 | import org.charts.dataviewer.api.data.PlotData |
13 | -import org.charts.dataviewer.api.trace.LineTrace | |
14 | 12 | import org.charts.dataviewer.api.trace.ScatterTrace |
15 | 13 | import org.charts.dataviewer.javafx.JavaFxDataViewer |
16 | 14 | import org.charts.dataviewer.utils.TraceColour |
17 | -import org.charts.dataviewer.utils.TraceMode | |
18 | 15 | import org.charts.dataviewer.utils.TraceVisibility |
19 | 16 | import java.net.URL |
20 | 17 | import java.util.* |
21 | 18 | |
22 | 19 | |
23 | 20 | |
... | ... | @@ -28,41 +25,16 @@ |
28 | 25 | @FXML |
29 | 26 | var dataListView = ListView<Pair<String, ArrayList<MessageData?>>>() |
30 | 27 | |
31 | -// @FXML | |
32 | -// var stackPanePlot = StackPane() | |
33 | - | |
34 | 28 | @FXML |
35 | 29 | var dataViewer = JavaFxDataViewer() |
36 | 30 | |
37 | -// @FXML | |
38 | -// var xaxisNumber: CategoryAxis = CategoryAxis() | |
39 | -// | |
40 | -// @FXML | |
41 | -// var yaxisNumber: NumberAxis = NumberAxis() | |
42 | -// | |
43 | -// @FXML | |
44 | -// lateinit var scatterChartNumber: ScatterChart<String, Number> | |
45 | -// | |
46 | -// @FXML | |
47 | -// var xaxisCategory: CategoryAxis = CategoryAxis() | |
48 | -// | |
49 | -// @FXML | |
50 | -// var yaxisCategory: CategoryAxis = CategoryAxis() | |
51 | -// | |
52 | -// @FXML | |
53 | -// lateinit var scatterChartCategory: ScatterChart<String, String> | |
54 | 31 | |
55 | 32 | override fun initialize(location: URL?, resources: ResourceBundle?) { |
56 | -// xaxisNumber.animated = false | |
57 | -// yaxisNumber.animated = false | |
58 | -// xaxisCategory.animated = false | |
59 | -// yaxisCategory.animated = false | |
60 | 33 | setObservableSelectedVesselListener() |
61 | 34 | dataListView.items = dataList |
62 | 35 | |
63 | 36 | |
64 | 37 | val plotData = PlotData() |
65 | - plotData.addTrace(createScatterTrace()) | |
66 | 38 | val config = DataViewerConfiguration() |
67 | 39 | config.showLegend(true) |
68 | 40 | config.setLegendInsidePlot(false) |
... | ... | @@ -85,6 +57,8 @@ |
85 | 57 | plotData.allTraces.clear() |
86 | 58 | config.setxAxisTitle("") |
87 | 59 | config.setyAxisTitle("") |
60 | + dataViewer.updateConfiguration(config) | |
61 | + | |
88 | 62 | dataViewer.resetPlot() |
89 | 63 | |
90 | 64 | return@addListener |
91 | 65 | |
92 | 66 | |
93 | 67 | |
... | ... | @@ -139,45 +113,12 @@ |
139 | 113 | } |
140 | 114 | |
141 | 115 | plotData.allTraces.clear() |
142 | -// plotData.addTrace(createScatterTrace()) | |
143 | 116 | config.setxAxisTitle("") |
144 | 117 | config.setyAxisTitle("") |
145 | - config.plotTitle = "No data selected" | |
146 | 118 | dataViewer.updateConfiguration(config) |
147 | 119 | dataViewer.updatePlot(plotData) |
148 | 120 | |
149 | -// stackPanePlot.children.add(dataViewer) | |
150 | - | |
151 | 121 | } |
152 | - | |
153 | - private fun createScatterTrace(): ScatterTrace<*>? { | |
154 | - val scatterTrace = ScatterTrace<Any>() | |
155 | - scatterTrace.setxArray(arrayOf("asdf", "fdsa", "asdfffe", "asdfe", "asfee3")) | |
156 | - scatterTrace.setyArray(arrayOf("pppp", "koojoi", "pp", "ii", "rty", "ert")) | |
157 | - scatterTrace.traceName = "MyScatterTrace" | |
158 | - scatterTrace.traceColour = TraceColour.PURPLE | |
159 | - scatterTrace.traceMode = TraceMode.MARKERS | |
160 | - return scatterTrace | |
161 | - } | |
162 | - | |
163 | - fun createLineTrace(): LineTrace<*>? { | |
164 | - val lineTrace = LineTrace<Any>() | |
165 | - lineTrace.setxArray(arrayOf("asdf", "fdsa", "asdfffe", "asdfe", "asfee3")) | |
166 | - lineTrace.setyArray(arrayOf(0.0, 1.0, 2.0, 3.0, 4.0, 5.0)) | |
167 | - lineTrace.traceName = "MyLineTrace" | |
168 | - lineTrace.traceColour = TraceColour.PURPLE | |
169 | - return lineTrace | |
170 | - } | |
171 | - | |
172 | -// private fun setChartCategoryVisible() { | |
173 | -// scatterChartCategory.isVisible = true | |
174 | -// scatterChartNumber.isVisible = false | |
175 | -// } | |
176 | -// | |
177 | -// private fun setChartNumberVisible() { | |
178 | -// scatterChartCategory.isVisible = false | |
179 | -// scatterChartNumber.isVisible = true | |
180 | -// } | |
181 | 122 | |
182 | 123 | private fun setObservableSelectedVesselListener() { |
183 | 124 | observableSelectedVessel.listeners.add(this) |
src/main/kotlin/application/controller/MapPanelController.kt
View file @
f39d90e
... | ... | @@ -52,7 +52,7 @@ |
52 | 52 | } |
53 | 53 | } |
54 | 54 | |
55 | - private fun updateMap(selectedMMSI: Int) { | |
55 | + private fun updateMap(selectedMMSI: String) { | |
56 | 56 | when (observableState.state) { |
57 | 57 | ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI) |
58 | 58 | CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI) |
... | ... | @@ -62,7 +62,7 @@ |
62 | 62 | |
63 | 63 | private fun setObservableVesselListener() { |
64 | 64 | observableVessel.listeners.add(object : MessageListener { |
65 | - override fun onValueChanged(newValue: MutableMap<Int?, Vessel>) { | |
65 | + override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { | |
66 | 66 | updateMap() |
67 | 67 | } |
68 | 68 | }) |
... | ... | @@ -73,6 +73,8 @@ |
73 | 73 | override fun onValueChanged(newValue: Vessel) { |
74 | 74 | if (newValue.mmsi != null){ |
75 | 75 | updateMap(newValue.mmsi) |
76 | + }else { | |
77 | + updateMap() | |
76 | 78 | } |
77 | 79 | } |
78 | 80 | }) |
src/main/kotlin/application/controller/VesselListPanelController.kt
View file @
f39d90e
... | ... | @@ -2,35 +2,65 @@ |
2 | 2 | |
3 | 3 | import application.model.MessageListener |
4 | 4 | import application.model.Vessel |
5 | -import application.model.observableVessel | |
6 | 5 | import application.model.observableSelectedVessel |
6 | +import application.model.observableVessel | |
7 | 7 | import javafx.collections.FXCollections |
8 | 8 | import javafx.collections.ObservableList |
9 | +import javafx.event.EventHandler | |
9 | 10 | import javafx.fxml.FXML |
10 | 11 | import javafx.fxml.Initializable |
11 | -import javafx.scene.control.ListView | |
12 | +import javafx.scene.control.* | |
13 | +import javafx.scene.input.MouseEvent | |
12 | 14 | import java.net.URL |
13 | 15 | import java.util.* |
14 | 16 | |
17 | + | |
15 | 18 | class VesselListPanelController : Initializable, MessageListener { |
16 | 19 | @FXML |
17 | - var shipListView: ListView<Int> = ListView() | |
20 | + var shipListView: ListView<String?> = ListView() | |
18 | 21 | |
22 | + private var shipList: ObservableList<String?> = FXCollections.observableArrayList() | |
19 | 23 | |
20 | - private var shipList: ObservableList<Int> = FXCollections.observableArrayList() | |
21 | - | |
22 | 24 | override fun initialize(location: URL?, resources: ResourceBundle?) { |
25 | + | |
26 | + | |
23 | 27 | shipListView.items = shipList |
24 | 28 | observableVessel.listeners.add(this) |
25 | 29 | shipListView.selectionModel.selectedItemProperty().addListener { _, _, newValue -> |
26 | - observableSelectedVessel.vessel = observableVessel.vessels[newValue]!! | |
30 | + if (newValue == null) { | |
31 | + observableSelectedVessel.vessel = Vessel(null) | |
32 | + } else { | |
33 | + observableSelectedVessel.vessel = observableVessel.vessels[newValue]!! | |
34 | + } | |
27 | 35 | } |
36 | + setCellFactory() | |
28 | 37 | } |
29 | 38 | |
30 | - override fun onValueChanged(newValue: MutableMap<Int?, Vessel>) { | |
39 | + override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { | |
31 | 40 | shipList.clear() |
32 | 41 | shipList.addAll(newValue.keys) |
33 | 42 | } |
34 | 43 | |
44 | + private fun setCellFactory() { | |
45 | + val selectionModel: MultipleSelectionModel<String?>? = shipListView.selectionModel | |
46 | + selectionModel?.selectionMode = SelectionMode.SINGLE | |
47 | + shipListView.setCellFactory { | |
48 | + val cell = ListCell<String?>() | |
49 | + cell.textProperty().bind(cell.itemProperty()) | |
50 | + cell.addEventFilter(MouseEvent.MOUSE_PRESSED) { event: MouseEvent -> | |
51 | + shipListView.requestFocus() | |
52 | + if (!cell.isEmpty) { | |
53 | + val index = cell.index | |
54 | + if (selectionModel!!.selectedIndices.contains(index)) { | |
55 | + selectionModel.clearSelection() | |
56 | + } else { | |
57 | + selectionModel.select(index) | |
58 | + } | |
59 | + event.consume() | |
60 | + } | |
61 | + } | |
62 | + cell | |
63 | + } | |
64 | + } | |
35 | 65 | } |
src/main/kotlin/application/model/Message.kt
View file @
f39d90e
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | import java.time.LocalDateTime |
4 | 4 | |
5 | 5 | class Message(split: List<String>) { |
6 | - val mmsi = MMSI(split[0].toIntOrNull()) | |
6 | + val mmsi = MMSI(if (split[0] == "") null else split[0]) | |
7 | 7 | val time = Time(LocalDateTime.parse(split[1])) |
8 | 8 | val latitude = Latitude(split[2].toDoubleOrNull()) |
9 | 9 | val longitude = Longitude(split[3].toDoubleOrNull()) |
10 | 10 | |
... | ... | @@ -20,9 +20,8 @@ |
20 | 20 | val draft = Draft(split[14].toDoubleOrNull()) |
21 | 21 | val cargo = Cargo(split[15].toIntOrNull()) |
22 | 22 | |
23 | - | |
24 | 23 | fun getHexColorStroke(): String { |
25 | - var hex = Integer.toHexString(this.mmsi.value!!) | |
24 | + var hex = Integer.toHexString(this.mmsi.value?.toInt()!!) | |
26 | 25 | if (hex.length > 6) { |
27 | 26 | hex = hex.substring(hex.length - 6) |
28 | 27 | } |
src/main/kotlin/application/model/MessageData.kt
View file @
f39d90e
src/main/kotlin/application/model/MessageListener.kt
View file @
f39d90e
src/main/kotlin/application/model/ObservableVessel.kt
View file @
f39d90e
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | class ObservableVessel { |
6 | 6 | val listeners: MutableList<MessageListener> = mutableListOf() |
7 | 7 | |
8 | - var vessels: MutableMap<Int?, Vessel> by Delegates.observable( | |
8 | + var vessels: MutableMap<String?, Vessel> by Delegates.observable( | |
9 | 9 | initialValue = mutableMapOf(), |
10 | 10 | onChange = { _, _, new -> |
11 | 11 | run { |
src/main/kotlin/application/model/Vessel.kt
View file @
f39d90e
... | ... | @@ -5,18 +5,8 @@ |
5 | 5 | import java.util.* |
6 | 6 | |
7 | 7 | |
8 | -class Vessel(val mmsi: Int?) { | |
8 | +class Vessel(val mmsi: String?) { | |
9 | 9 | val messages: SortedMap<LocalDateTime, Message> = sortedMapOf() |
10 | - | |
11 | - fun getAllTimeInMilliSeconde(): ArrayList<Long> { | |
12 | - val timeList = arrayListOf<Long>() | |
13 | - var timeInMilliSeconde: Long | |
14 | - messages.forEach { | |
15 | - timeInMilliSeconde = it.value.time.value.toEpochSecond(ZoneOffset.UTC).toInt().toLong() | |
16 | - timeList.add(timeInMilliSeconde) | |
17 | - } | |
18 | - return timeList | |
19 | - } | |
20 | 10 | |
21 | 11 | fun getAllTime(): ArrayList<MessageData?> { |
22 | 12 | val timeList = arrayListOf<MessageData?>() |
src/main/kotlin/application/model/VesselGenerator.kt
View file @
f39d90e
... | ... | @@ -4,9 +4,9 @@ |
4 | 4 | import java.util.* |
5 | 5 | import kotlin.collections.ArrayList |
6 | 6 | |
7 | -fun createVesselCollection(file: File) : SortedMap<Int, Vessel> { | |
7 | +fun createVesselCollection(file: File) : SortedMap<String, Vessel> { | |
8 | 8 | val messages : ArrayList<Message> = arrayListOf() |
9 | - val vessels: SortedMap<Int, Vessel> = sortedMapOf() | |
9 | + val vessels: SortedMap<String, Vessel> = sortedMapOf() | |
10 | 10 | |
11 | 11 | file.forEachLine { |
12 | 12 | val arrayMessage = it.split(",") |
src/main/kotlin/map/MapDisplayer.kt
View file @
f39d90e
... | ... | @@ -44,7 +44,7 @@ |
44 | 44 | } |
45 | 45 | } |
46 | 46 | |
47 | -fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: Int) { | |
47 | +fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) { | |
48 | 48 | clearMap(map) |
49 | 49 | observableVessel.vessels.forEach { (_, value) -> |
50 | 50 | value.messages.forEach { (_, message) -> |
... | ... | @@ -67,7 +67,7 @@ |
67 | 67 | map.execScript("myMap.addLayer(markerClusters);") |
68 | 68 | } |
69 | 69 | |
70 | -fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: Int) { | |
70 | +fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) { | |
71 | 71 | clearMap(map) |
72 | 72 | observableVessel.vessels.forEach { (_, value) -> |
73 | 73 | value.messages.forEach { (_, message) -> |
... | ... | @@ -90,7 +90,7 @@ |
90 | 90 | } |
91 | 91 | } |
92 | 92 | |
93 | -fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: Int) { | |
93 | +fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) { | |
94 | 94 | clearMap(map) |
95 | 95 | observableVessel.vessels.forEach { (_, value) -> |
96 | 96 | value.messages.forEach { (_, message) -> |
src/main/resources/gui/vesselListPanel.fxml
View file @
f39d90e
1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | 2 | |
3 | +<?import javafx.geometry.*?> | |
3 | 4 | <?import javafx.scene.control.*?> |
4 | 5 | <?import javafx.scene.layout.*?> |
6 | +<?import javafx.scene.text.*?> | |
5 | 7 | |
6 | -<BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller.VesselListPanelController"> | |
7 | - | |
8 | - <top> | |
9 | - <AnchorPane prefHeight="33.0" prefWidth="200.0" BorderPane.alignment="CENTER"> | |
10 | - <children> | |
11 | - <Button layoutX="74.0" layoutY="2.0" mnemonicParsing="false" text="Button" fx:id="button"/> | |
12 | - </children></AnchorPane> | |
13 | - </top> | |
8 | +<BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller.VesselListPanelController"> | |
14 | 9 | <center> |
15 | - <ListView fx:id="shipListView" prefHeight="105.0" prefWidth="200.0" /> | |
10 | + <ListView fx:id="shipListView" prefHeight="50.0" prefWidth="200.0" /> | |
16 | 11 | </center> |
12 | + <top> | |
13 | + <TextFlow prefHeight="28.0" prefWidth="200.0" style="-fx-font-weight: bold;" textAlignment="CENTER" BorderPane.alignment="CENTER"> | |
14 | + <children> | |
15 | + <Text scaleX="1.5" scaleY="1.5" strokeType="OUTSIDE" strokeWidth="0.0" text="MMSI" textAlignment="CENTER" /> | |
16 | + </children> | |
17 | + <BorderPane.margin> | |
18 | + <Insets /> | |
19 | + </BorderPane.margin> | |
20 | + <padding> | |
21 | + <Insets top="5.0" /> | |
22 | + </padding> | |
23 | + </TextFlow> | |
24 | + </top> | |
17 | 25 | </BorderPane> |