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> |