Commit 3b26be8f9997f5c644d7ffb3a76944f151e66325

Authored by lsagona
1 parent 8108656dd1
Exists in master and in 1 other branch dev

controle the time with slider

Showing 19 changed files with 243 additions and 56 deletions Inline Diff

src/main/kotlin/application/controller/DataPanelController.kt View file @ 3b26be8
package application.controller 1 1 package application.controller
2 2
import application.model.* 3 3 import application.model.*
import javafx.collections.FXCollections 4 4 import javafx.collections.FXCollections
import javafx.collections.ObservableList 5 5 import javafx.collections.ObservableList
import javafx.fxml.FXML 6 6 import javafx.fxml.FXML
import javafx.fxml.Initializable 7 7 import javafx.fxml.Initializable
import javafx.scene.control.ListCell 8 8 import javafx.scene.control.ListCell
import javafx.scene.control.ListView 9 9 import javafx.scene.control.ListView
import org.charts.dataviewer.api.config.DataViewerConfiguration 10 10 import org.charts.dataviewer.api.config.DataViewerConfiguration
import org.charts.dataviewer.api.data.PlotData 11 11 import org.charts.dataviewer.api.data.PlotData
import org.charts.dataviewer.api.trace.ScatterTrace 12 12 import org.charts.dataviewer.api.trace.ScatterTrace
import org.charts.dataviewer.javafx.JavaFxDataViewer 13 13 import org.charts.dataviewer.javafx.JavaFxDataViewer
import org.charts.dataviewer.utils.TraceColour 14 14 import org.charts.dataviewer.utils.TraceColour
import org.charts.dataviewer.utils.TraceVisibility 15 15 import org.charts.dataviewer.utils.TraceVisibility
import java.net.URL 16 16 import java.net.URL
import java.util.* 17 17 import java.util.*
18 18
19 19
class DataPanelController : Initializable, SelectedVesselListener { 20 20 class DataPanelController : Initializable, SelectedVesselListener {
private var dataList: ObservableList<Pair<String, ArrayList<MessageData?>>> = FXCollections.observableArrayList() 21 21 private var dataList: ObservableList<Pair<String, ArrayList<MessageData?>>> = FXCollections.observableArrayList()
private lateinit var timeData: ArrayList<MessageData?> 22 22 private lateinit var timeData: ArrayList<MessageData?>
23 23
24 24
@FXML 25 25 @FXML
var dataListView = ListView<Pair<String, ArrayList<MessageData?>>>() 26 26 var dataListView = ListView<Pair<String, ArrayList<MessageData?>>>()
27 27
@FXML 28 28 @FXML
var dataViewer = JavaFxDataViewer() 29 29 var dataViewer = JavaFxDataViewer()
30 30
31 31
override fun initialize(location: URL?, resources: ResourceBundle?) { 32 32 override fun initialize(location: URL?, resources: ResourceBundle?) {
setObservableSelectedVesselListener() 33 33 setObservableSelectedVesselListener()
dataListView.items = dataList 34 34 dataListView.items = dataList
35 35
36 36
val plotData = PlotData() 37 37 val plotData = PlotData()
val config = DataViewerConfiguration() 38 38 val config = DataViewerConfiguration()
config.showLegend(true) 39 39 config.showLegend(true)
config.setLegendInsidePlot(false) 40 40 config.setLegendInsidePlot(false)
41 41
dataListView.setCellFactory { 42 42 dataListView.setCellFactory {
object : ListCell<Pair<String, ArrayList<MessageData?>>?>() { 43 43 object : ListCell<Pair<String, ArrayList<MessageData?>>?>() {
override fun updateItem(item: Pair<String, ArrayList<MessageData?>>?, empty: Boolean) { 44 44 override fun updateItem(item: Pair<String, ArrayList<MessageData?>>?, empty: Boolean) {
super.updateItem(item, empty) 45 45 super.updateItem(item, empty)
text = if (empty) { 46 46 text = if (empty) {
null 47 47 null
} else { 48 48 } else {
item?.first 49 49 item?.first
} 50 50 }
} 51 51 }
} 52 52 }
} 53 53 }
54 54
dataListView.selectionModel.selectedItemProperty().addListener { _, _, newValue -> 55 55 dataListView.selectionModel.selectedItemProperty().addListener { _, _, newValue ->
if (newValue == null) { 56 56 if (newValue == null) {
plotData.allTraces.clear() 57 57 plotData.allTraces.clear()
config.setxAxisTitle("") 58 58 config.setxAxisTitle("")
config.setyAxisTitle("") 59 59 config.setyAxisTitle("")
dataViewer.updateConfiguration(config) 60 60 dataViewer.updateConfiguration(config)
61 61
dataViewer.resetPlot() 62 62 dataViewer.resetPlot()
63 63
return@addListener 64 64 return@addListener
} 65 65 }
66 66
val getValueVisitorX = GetValueVisitor() 67 67 val getValueVisitorX = GetValueVisitor()
val getValueVisitorY = GetValueVisitor() 68 68 val getValueVisitorY = GetValueVisitor()
69 69
val arrayListStringX = arrayListOf<String>() 70 70 val arrayListStringX = arrayListOf<String>()
val arrayListDoubleX = arrayListOf<Double>() 71 71 val arrayListDoubleX = arrayListOf<Double>()
val arrayListStringY = arrayListOf<String>() 72 72 val arrayListStringY = arrayListOf<String>()
val arrayListDoubleY = arrayListOf<Double>() 73 73 val arrayListDoubleY = arrayListOf<Double>()
74 74
for (x in 0 until newValue.second.size) { 75 75 for (x in 0 until newValue.second.size) {
timeData[x]?.accept(getValueVisitorX) 76 76 timeData[x]?.accept(getValueVisitorX)
newValue.second[x]?.accept(getValueVisitorY) 77 77 newValue.second[x]?.accept(getValueVisitorY)
78 78
if (getValueVisitorY.value.toDoubleOrNull() == null) { 79 79 if (getValueVisitorY.value.toDoubleOrNull() == null) {
arrayListStringX.add(getValueVisitorX.value) 80 80 arrayListStringX.add(getValueVisitorX.value)
arrayListStringY.add(getValueVisitorY.value) 81 81 arrayListStringY.add(getValueVisitorY.value)
} else { 82 82 } else {
arrayListStringX.add(getValueVisitorX.value) 83 83 arrayListStringX.add(getValueVisitorX.value)
arrayListDoubleY.add(getValueVisitorY.value.toDouble()) 84 84 arrayListDoubleY.add(getValueVisitorY.value.toDouble())
} 85 85 }
} 86 86 }
87 87
val scatterTrace = ScatterTrace<Any>() 88 88 val scatterTrace = ScatterTrace<Any>()
scatterTrace.traceColour = TraceColour.RED 89 89 scatterTrace.traceColour = TraceColour.RED
scatterTrace.traceVisibility = TraceVisibility.TRUE 90 90 scatterTrace.traceVisibility = TraceVisibility.TRUE
91 91
val serieStringX: Array<String> = arrayListStringX.toTypedArray() 92 92 val serieStringX: Array<String> = arrayListStringX.toTypedArray()
// val serieDoubleX: Array<Double> = arrayListDoubleX.toTypedArray() 93 93 // val serieDoubleX: Array<Double> = arrayListDoubleX.toTypedArray()
val serieStringY: Array<String> = arrayListStringY.toTypedArray() 94 94 val serieStringY: Array<String> = arrayListStringY.toTypedArray()
val serieDoubleY: Array<Double> = arrayListDoubleY.toTypedArray() 95 95 val serieDoubleY: Array<Double> = arrayListDoubleY.toTypedArray()
96 96
if (getValueVisitorY.value.toDoubleOrNull() == null) { 97 97 if (getValueVisitorY.value.toDoubleOrNull() == null) {
scatterTrace.setxArray(serieStringX) 98 98 scatterTrace.setxArray(serieStringX)
scatterTrace.setyArray(serieStringY) 99 99 scatterTrace.setyArray(serieStringY)
} else { 100 100 } else {
scatterTrace.setxArray(serieStringX) 101 101 scatterTrace.setxArray(serieStringX)
scatterTrace.setyArray(serieDoubleY) 102 102 scatterTrace.setyArray(serieDoubleY)
} 103 103 }
104 104
config.plotTitle = "" 105 105 config.plotTitle = ""
config.setxAxisTitle("Date") 106 106 config.setxAxisTitle("Time (s)")
config.setyAxisTitle(newValue.first) 107 107 config.setyAxisTitle(newValue.first)
dataViewer.resetPlot() 108 108 dataViewer.resetPlot()
plotData.allTraces.clear() 109 109 plotData.allTraces.clear()
plotData.addTrace(scatterTrace) 110 110 plotData.addTrace(scatterTrace)
dataViewer.updateConfiguration(config) 111 111 dataViewer.updateConfiguration(config)
dataViewer.updatePlot(plotData) 112 112 dataViewer.updatePlot(plotData)
113 113
} 114 114 }
115 115
plotData.allTraces.clear() 116 116 plotData.allTraces.clear()
config.setxAxisTitle("") 117 117 config.setxAxisTitle("")
config.setyAxisTitle("") 118 118 config.setyAxisTitle("")
config.plotTitle = "" 119 119 config.plotTitle = ""
dataViewer.updateConfiguration(config) 120 120 dataViewer.updateConfiguration(config)
dataViewer.updatePlot(plotData) 121 121 dataViewer.updatePlot(plotData)
122 122
} 123 123 }
124 124
private fun setObservableSelectedVesselListener() { 125 125 private fun setObservableSelectedVesselListener() {
observableSelectedVessel.listeners.add(this) 126 126 observableSelectedVessel.listeners.add(this)
} 127 127 }
128 128
private fun populateTime(vessel: Vessel): ArrayList<MessageData?> { 129 129 private fun populateTime(vessel: Vessel): ArrayList<MessageData?> {
val allTime: ArrayList<MessageData?> = vessel.getAllTime() 130 130 val allTime: ArrayList<MessageData?> = vessel.getAllTime()
allTime.sortBy { (it as Time).value } 131 131 allTime.sortBy { (it as Time).value }
132 132
return allTime 133 133 return allTime
} 134 134 }
135 135
private fun populateLatitude(vessel: Vessel): ArrayList<MessageData?> { 136 136 private fun populateLatitude(vessel: Vessel): ArrayList<MessageData?> {
val allLatitude: ArrayList<MessageData?> = vessel.getAllLatitude() 137 137 val allLatitude: ArrayList<MessageData?> = vessel.getAllLatitude()
allLatitude.sortBy { (it as Latitude).value } 138 138 allLatitude.sortBy { (it as Latitude).value }
139 139
return allLatitude 140 140 return allLatitude
} 141 141 }
142 142
private fun populateLongitude(vessel: Vessel): ArrayList<MessageData?> { 143 143 private fun populateLongitude(vessel: Vessel): ArrayList<MessageData?> {
val allLongitude: ArrayList<MessageData?> = vessel.getAllLongitude() 144 144 val allLongitude: ArrayList<MessageData?> = vessel.getAllLongitude()
allLongitude.sortBy { (it as Longitude).value } 145 145 allLongitude.sortBy { (it as Longitude).value }
146 146
return allLongitude 147 147 return allLongitude
} 148 148 }
149 149
private fun populateSpeedOverGround(vessel: Vessel): ArrayList<MessageData?> { 150 150 private fun populateSpeedOverGround(vessel: Vessel): ArrayList<MessageData?> {
val allSpeedOverGround: ArrayList<MessageData?> = vessel.getAllSpeedOverGround() 151 151 val allSpeedOverGround: ArrayList<MessageData?> = vessel.getAllSpeedOverGround()
allSpeedOverGround.sortBy { (it as SpeedOverGround).value } 152 152 allSpeedOverGround.sortBy { (it as SpeedOverGround).value }
153 153
return allSpeedOverGround 154 154 return allSpeedOverGround
} 155 155 }
156 156
private fun populateCourseOverGround(vessel: Vessel): ArrayList<MessageData?> { 157 157 private fun populateCourseOverGround(vessel: Vessel): ArrayList<MessageData?> {
val allCourseOverGround: ArrayList<MessageData?> = vessel.getAllCourseOverGround() 158 158 val allCourseOverGround: ArrayList<MessageData?> = vessel.getAllCourseOverGround()
allCourseOverGround.sortBy { (it as CourseOverGround).value } 159 159 allCourseOverGround.sortBy { (it as CourseOverGround).value }
160 160
return allCourseOverGround 161 161 return allCourseOverGround
} 162 162 }
163 163
private fun populateHeading(vessel: Vessel): ArrayList<MessageData?> { 164 164 private fun populateHeading(vessel: Vessel): ArrayList<MessageData?> {
val allHeading: ArrayList<MessageData?> = vessel.getAllHeading() 165 165 val allHeading: ArrayList<MessageData?> = vessel.getAllHeading()
allHeading.sortBy { (it as Heading).value } 166 166 allHeading.sortBy { (it as Heading).value }
167 167
return allHeading 168 168 return allHeading
} 169 169 }
170 170
private fun populateVesselName(vessel: Vessel): ArrayList<MessageData?> { 171 171 private fun populateVesselName(vessel: Vessel): ArrayList<MessageData?> {
val allVesselName: ArrayList<MessageData?> = vessel.getAllVesselName() 172 172 val allVesselName: ArrayList<MessageData?> = vessel.getAllVesselName()
allVesselName.sortBy { (it as VesselName).value } 173 173 allVesselName.sortBy { (it as VesselName).value }
174 174
return allVesselName 175 175 return allVesselName
} 176 176 }
177 177
private fun populateIMO(vessel: Vessel): ArrayList<MessageData?> { 178 178 private fun populateIMO(vessel: Vessel): ArrayList<MessageData?> {
val allIMO: ArrayList<MessageData?> = vessel.getAllIMO() 179 179 val allIMO: ArrayList<MessageData?> = vessel.getAllIMO()
allIMO.sortBy { (it as IMO).value } 180 180 allIMO.sortBy { (it as IMO).value }
181 181
return allIMO 182 182 return allIMO
} 183 183 }
184 184
private fun populateCallSign(vessel: Vessel): ArrayList<MessageData?> { 185 185 private fun populateCallSign(vessel: Vessel): ArrayList<MessageData?> {
val allCallSign: ArrayList<MessageData?> = vessel.getAllCallSign() 186 186 val allCallSign: ArrayList<MessageData?> = vessel.getAllCallSign()
allCallSign.sortBy { (it as CallSign).value } 187 187 allCallSign.sortBy { (it as CallSign).value }
188 188
return allCallSign 189 189 return allCallSign
} 190 190 }
191 191
private fun populateVesselType(vessel: Vessel): ArrayList<MessageData?> { 192 192 private fun populateVesselType(vessel: Vessel): ArrayList<MessageData?> {
val allVesselType: ArrayList<MessageData?> = vessel.getAllVesselType() 193 193 val allVesselType: ArrayList<MessageData?> = vessel.getAllVesselType()
allVesselType.sortBy { (it as VesselType).value } 194 194 allVesselType.sortBy { (it as VesselType).value }
195 195
return allVesselType 196 196 return allVesselType
} 197 197 }
198 198
private fun populateStatus(vessel: Vessel): ArrayList<MessageData?> { 199 199 private fun populateStatus(vessel: Vessel): ArrayList<MessageData?> {
val allStatus: ArrayList<MessageData?> = vessel.getAllStatus() 200 200 val allStatus: ArrayList<MessageData?> = vessel.getAllStatus()
allStatus.sortBy { (it as Status).value } 201 201 allStatus.sortBy { (it as Status).value }
src/main/kotlin/application/controller/MapPanelController.kt View file @ 3b26be8
package application.controller 1 1 package application.controller
2 2
import application.model.* 3 3 import application.model.*
import application.model.State.* 4 4 import application.model.MapState.*
import javafx.fxml.FXML 5 5 import javafx.fxml.FXML
import javafx.fxml.Initializable 6 6 import javafx.fxml.Initializable
import javafx.scene.layout.StackPane 7 7 import javafx.scene.layout.StackPane
import map.* 8 8 import map.*
import java.net.URL 9 9 import java.net.URL
import java.util.* 10 10 import java.util.*
11 11
class MapPanelController : Initializable { 12 12 class MapPanelController : Initializable {
13 13
@FXML 14 14 @FXML
private lateinit var map: StackPane 15 15 private lateinit var map: StackPane
16 16
private val mapView = LeafletMapView() 17 17 private val mapView = LeafletMapView()
18 18
19 19
override fun initialize(location: URL?, resources: ResourceBundle?) { 20 20 override fun initialize(location: URL?, resources: ResourceBundle?) {
mapView.displayMap(MapConfig()) 21 21 mapView.displayMap(MapConfig())
setObservableVesselListener() 22 22 setObservableVesselListener()
setObservableSelectedVesselListener() 23 23 setObservableSelectedVesselListener()
setStateListener() 24 24 setStateListener()
25 observableCurrentTime()
26
/*val completeFutureMap: CompletableFuture<Worker.State> = mapView.displayMap(MapConfig()) 25 27 /*val completeFutureMap: CompletableFuture<Worker.State> = mapView.displayMap(MapConfig())
completeFutureMap.whenComplete{ 26 28 completeFutureMap.whenComplete{
workerState, _ -> 27 29 workerState, _ ->
if (workerState == Worker.State.SUCCEEDED) { 28 30 if (workerState == Worker.State.SUCCEEDED) {
} 29 31 }
}*/ 30 32 }*/
map.children.add(mapView) 31 33 map.children.add(mapView)
map.children 32 34 map.children
} 33 35 }
34 36
private fun setStateListener() { 35 37 private fun setStateListener() {
observableState.listeners.add(object : StateListener { 36 38 observableMapState.listeners.add(object : StateListener {
override fun onValueChanged(newValue: State) { 37 39 override fun onValueChanged(newValue: MapState) {
if (observableSelectedVessel.vessel.mmsi != null) { 38 40 if (observableSelectedVessel.vessel.mmsi != null) {
updateMap(observableSelectedVessel.vessel.mmsi!!) 39 41 updateMap(observableSelectedVessel.vessel.mmsi!!)
} else { 40 42 } else {
updateMap() 41 43 updateMap()
} 42 44 }
} 43 45 }
}) 44 46 })
} 45 47 }
46 48
49 private fun observableCurrentTime() {
50 observableCurrentTime.listeners.add(object : CurrentTime{
51 override fun onValueChanged(newValue: Int) {
52 updateMap()
53 }
54 })
55 }
56
private fun updateMap() { 47 57 private fun updateMap() {
when (observableState.state) { 48 58 if (observableIsReplayState.value){
ALL_MESSAGES -> displayAllMessageOnMap(mapView) 49 59 displayTargetedVessels(mapView)
CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView) 50 60 } else {
HEAT_MAP -> displayHeatMapOnMap(mapView) 51 61 when (observableMapState.state) {
62 ALL_MESSAGES -> displayAllMessageOnMap(mapView)
63 CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView)
64 HEAT_MAP -> displayHeatMapOnMap(mapView)
65 }
} 52 66 }
} 53 67 }
54 68
private fun updateMap(selectedMMSI: String) { 55 69 private fun updateMap(selectedMMSI: String) {
when (observableState.state) { 56 70 when (observableMapState.state) {
ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI) 57 71 ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI)
CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI) 58 72 CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI)
HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI) 59 73 HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI)
} 60 74 }
} 61 75 }
62 76
private fun setObservableVesselListener() { 63 77 private fun setObservableVesselListener() {
observableVessel.listeners.add(object : MessageListener { 64 78 observableVessel.listeners.add(object : MessageListener {
override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { 65 79 override fun onValueChanged(newValue: MutableMap<String?, Vessel>) {
updateMap() 66 80 updateMap()
} 67 81 }
}) 68 82 })
} 69 83 }
70 84
private fun setObservableSelectedVesselListener() { 71 85 private fun setObservableSelectedVesselListener() {
observableSelectedVessel.listeners.add(object : SelectedVesselListener { 72 86 observableSelectedVessel.listeners.add(object : SelectedVesselListener {
override fun onValueChanged(newValue: Vessel) { 73 87 override fun onValueChanged(newValue: Vessel) {
if (newValue.mmsi != null){ 74 88 if (newValue.mmsi != null){
updateMap(newValue.mmsi) 75 89 updateMap(newValue.mmsi)
}else { 76 90 }else {
updateMap() 77 91 updateMap()
} 78 92 }
} 79 93 }
src/main/kotlin/application/controller/MenuBarController.kt View file @ 3b26be8
package application.controller 1 1 package application.controller
2 2
import application.model.State.* 3 3 import application.model.MapState.*
import application.model.createVesselCollection 4 4 import application.model.createVesselCollection
import application.model.observableState 5 5 import application.model.observableMapState
import application.model.observableVessel 6 6 import application.model.observableVessel
import javafx.event.EventHandler 7 7 import javafx.event.EventHandler
import javafx.fxml.FXML 8 8 import javafx.fxml.FXML
import javafx.fxml.Initializable 9 9 import javafx.fxml.Initializable
import javafx.scene.control.Alert 10 10 import javafx.scene.control.Alert
import javafx.scene.control.CheckMenuItem 11 11 import javafx.scene.control.CheckMenuItem
import javafx.scene.control.MenuBar 12 12 import javafx.scene.control.MenuBar
import javafx.scene.control.MenuItem 13 13 import javafx.scene.control.MenuItem
import javafx.stage.FileChooser 14 14 import javafx.stage.FileChooser
import java.net.URL 15 15 import java.net.URL
import java.util.* 16 16 import java.util.*
17 17
class MenuBarController : Initializable { 18 18 class MenuBarController : Initializable {
19 19
@FXML 20 20 @FXML
var menuBar: MenuBar = MenuBar() 21 21 var menuBar: MenuBar = MenuBar()
22 22
@FXML 23 23 @FXML
var import: MenuItem = MenuItem() 24 24 var import: MenuItem = MenuItem()
25 25
@FXML 26 26 @FXML
var allMessages: CheckMenuItem = CheckMenuItem() 27 27 var allMessages: CheckMenuItem = CheckMenuItem()
28 28
@FXML 29 29 @FXML
var clusteredMessage: CheckMenuItem = CheckMenuItem() 30 30 var clusteredMessage: CheckMenuItem = CheckMenuItem()
31 31
@FXML 32 32 @FXML
var heatMap: CheckMenuItem = CheckMenuItem() 33 33 var heatMap: CheckMenuItem = CheckMenuItem()
34 34
override fun initialize(location: URL?, resources: ResourceBundle?) { 35 35 override fun initialize(location: URL?, resources: ResourceBundle?) {
36 36
setOnActionImportButton() 37 37 setOnActionImportButton()
38 38
setOnActionAllMessageButton() 39 39 setOnActionAllMessageButton()
setOnActionClusteredMessageButton() 40 40 setOnActionClusteredMessageButton()
setOnActionHeatMapButton() 41 41 setOnActionHeatMapButton()
observableState.state = CLUSTERED_MESSAGES 42 42 observableMapState.state = CLUSTERED_MESSAGES
allMessages.isSelected = false 43 43 allMessages.isSelected = false
clusteredMessage.isSelected = true 44 44 clusteredMessage.isSelected = true
heatMap.isSelected = false 45 45 heatMap.isSelected = false
46 46
} 47 47 }
48 48
private fun setOnActionImportButton() { 49 49 private fun setOnActionImportButton() {
import.onAction = EventHandler { 50 50 import.onAction = EventHandler {
val fileChooser = FileChooser() 51 51 val fileChooser = FileChooser()
fileChooser.title = "Choose a file to import" 52 52 fileChooser.title = "Choose a file to import"
val window = menuBar.scene.window 53 53 val window = menuBar.scene.window
val file = fileChooser.showOpenDialog(window) 54 54 val file = fileChooser.showOpenDialog(window)
try { 55 55 try {
if (file.extension != "csv") { 56 56 if (file.extension != "csv") {
val alert = Alert(Alert.AlertType.WARNING) 57 57 val alert = Alert(Alert.AlertType.WARNING)
alert.title = "Warning Alert" 58 58 alert.title = "Warning Alert"
alert.headerText = "Wrong file format." 59 59 alert.headerText = "Wrong file format."
alert.contentText = "Please choose ร  .csv file." 60 60 alert.contentText = "Please choose ร  .csv file."
alert.showAndWait() 61 61 alert.showAndWait()
} 62 62 }
val vessels = createVesselCollection(file) 63 63 val vessels = createVesselCollection(file)
observableVessel.vessels.clear() 64 64 observableVessel.vessels.clear()
observableVessel.vessels = vessels 65 65 observableVessel.vessels = vessels
} catch (ignore: IllegalStateException) { 66 66 } catch (ignore: IllegalStateException) {
67 67
} 68 68 }
} 69 69 }
} 70 70 }
71 71
private fun setOnActionAllMessageButton() { 72 72 private fun setOnActionAllMessageButton() {
allMessages.onAction = EventHandler { 73 73 allMessages.onAction = EventHandler {
observableState.state = ALL_MESSAGES 74 74 observableMapState.state = ALL_MESSAGES
allMessages.isSelected = true 75 75 allMessages.isSelected = true
clusteredMessage.isSelected = false 76 76 clusteredMessage.isSelected = false
heatMap.isSelected = false 77 77 heatMap.isSelected = false
} 78 78 }
} 79 79 }
80 80
private fun setOnActionClusteredMessageButton() { 81 81 private fun setOnActionClusteredMessageButton() {
clusteredMessage.onAction = EventHandler { 82 82 clusteredMessage.onAction = EventHandler {
observableState.state = CLUSTERED_MESSAGES 83 83 observableMapState.state = CLUSTERED_MESSAGES
heatMap.isSelected = false 84 84 heatMap.isSelected = false
allMessages.isSelected = false 85 85 allMessages.isSelected = false
clusteredMessage.isSelected = true 86 86 clusteredMessage.isSelected = true
} 87 87 }
} 88 88 }
src/main/kotlin/application/controller/TimePanel.kt View file @ 3b26be8
File was created 1 package application.controller
2
3 import application.model.*
4 import javafx.fxml.FXML
5 import javafx.fxml.Initializable
6 import javafx.scene.control.Button
7 import javafx.scene.control.Slider
8 import java.net.URL
9 import java.util.*
10
11
12 class TimePanel : Initializable {
13
14 @FXML
15 var timeSlider = Slider()
16
17 @FXML
18 var timeStop = Button()
19
20 @FXML
21 var timePlay = Button()
22
23
24 override fun initialize(location: URL?, resources: ResourceBundle?) {
25 setSliderMinMax()
26 setSliderListener()
27
28
29 }
30
31 private fun setSliderMinMax() {
32 observableVessel.listeners.add(object : MessageListener{
33 override fun onValueChanged(newValue: MutableMap<String?, Vessel>) {
src/main/kotlin/application/model/Context.kt View file @ 3b26be8
package application.model 1 1 package application.model
2 2
val observableVessel: ObservableVessel = ObservableVessel() 3 3 val observableVessel: ObservableVessel = ObservableVessel()
4 4
val observableSelectedVessel: ObservableSelectedVessel = ObservableSelectedVessel() 5 5 val observableSelectedVessel: ObservableSelectedVessel = ObservableSelectedVessel()
6 6
val observableState: ObservableState = ObservableState() 7 7 val observableMapState: ObservableMapState = ObservableMapState()
8
9 val observableIsReplayState: ObservableReplayState = ObservableReplayState()
src/main/kotlin/application/model/CurrentTime.kt View file @ 3b26be8
File was created 1 package application.model
2
3 interface CurrentTime {
4 fun onValueChanged(newValue: Int)
src/main/kotlin/application/model/MapState.kt View file @ 3b26be8
File was created 1 package application.model
2
3 enum class MapState {
4 ALL_MESSAGES,
5 CLUSTERED_MESSAGES,
6 HEAT_MAP
src/main/kotlin/application/model/ObservableCurrentTime.kt View file @ 3b26be8
File was created 1 package application.model
2
3 import kotlin.properties.Delegates
4
5 class ObservableCurrentTime {
6
7 val listeners: MutableList<CurrentTime> = mutableListOf()
8
9 var value: Int by Delegates.observable(
10 initialValue = 0,
11 onChange = { _, _, new ->
12 run {
13 listeners.forEach {
14 it.onValueChanged(new)
15 }
src/main/kotlin/application/model/ObservableMapState.kt View file @ 3b26be8
File was created 1 package application.model
2
3 import kotlin.properties.Delegates
4
5 class ObservableMapState {
6 val listeners: MutableList<StateListener> = mutableListOf()
7
8 var state: MapState by Delegates.observable(
9 initialValue = MapState.CLUSTERED_MESSAGES,
10 onChange = { _, _, new ->
11 run {
12 listeners.forEach {
13 it.onValueChanged(new)
14 }
15 }
src/main/kotlin/application/model/ObservableReplayState.kt View file @ 3b26be8
File was created 1 package application.model
2
3 import kotlin.properties.Delegates
4
5 class ObservableReplayState {
6
7 val listeners: MutableList<ReplayState> = mutableListOf()
8
9 var value: Boolean by Delegates.observable(
10 initialValue = true,
11 onChange = { _, _, new ->
12 run {
13 listeners.forEach {
14 it.onValueChanged(new)
15 }
src/main/kotlin/application/model/ObservableState.kt View file @ 3b26be8
package application.model 1 File was deleted
2
import kotlin.properties.Delegates 3
4
class ObservableState { 5
val listeners: MutableList<StateListener> = mutableListOf() 6
7
var state: State by Delegates.observable( 8
initialValue = State.CLUSTERED_MESSAGES, 9
onChange = { _, _, new -> 10
run { 11
listeners.forEach { 12
it.onValueChanged(new) 13
} 14
} 15
src/main/kotlin/application/model/ReplayState.kt View file @ 3b26be8
File was created 1 package application.model
2
3 interface ReplayState {
4 fun onValueChanged(newValue: Boolean)
src/main/kotlin/application/model/State.kt View file @ 3b26be8
package application.model 1 File was deleted
2
enum class State { 3
ALL_MESSAGES, 4
CLUSTERED_MESSAGES, 5
HEAT_MAP 6
src/main/kotlin/application/model/StateListener.kt View file @ 3b26be8
package application.model 1 1 package application.model
2 2
interface StateListener { 3 3 interface StateListener {
fun onValueChanged(newValue: State) 4 4 fun onValueChanged(newValue: MapState)
} 5 5 }
src/main/kotlin/application/model/Vessel.kt View file @ 3b26be8
package application.model 1 1 package application.model
2 2
import java.time.LocalDateTime 3
import java.time.ZoneOffset 4
import java.util.* 5 3 import java.util.*
6 4
7 5
class Vessel(val mmsi: String?) { 8 6 class Vessel(val mmsi: String?) {
val messages: SortedMap<LocalDateTime, Message> = sortedMapOf() 9 7 val messages: SortedMap<Long, Message> = sortedMapOf()
8 var messageToDisplay: Message? = null
9 get() {
10 // messages.forEach { (key, value) ->
11 // if(observableCurrentTime.value < key) {
12 // field = value
13 // return@forEach
14 // }
15 // }
16 field = messages.asSequence().map{ it }.firstOrNull {observableCurrentTime.value < it.key}.let { it?.value }
17 return field
18 }
10 19
20 // val timesNormalized : SortedMap<Long, LocalDateTime> = sortedMapOf()
21
22 // fun getAllNormalizedDate(): SortedMap<Long, LocalDateTime> {
23 // var offset: Long? = null
24 // if(timesNormalized.size == 0){
25 // messages.keys.forEach {
26 // val currentTime = it.toEpochSecond(ZoneOffset.UTC)
27 // if(offset == null){
28 // offset = currentTime
29 // }
30 // timesNormalized[currentTime - offset!!]= it
31 // }
32 // }
33 // return timesNormalized
34 // }
35
fun getAllTime(): ArrayList<MessageData?> { 11 36 fun getAllTime(): ArrayList<MessageData?> {
val timeList = arrayListOf<MessageData?>() 12 37 val timeList = arrayListOf<MessageData?>()
messages.forEach { 13 38 messages.forEach {
timeList.add(it.value.time) 14 39 timeList.add(it.value.time)
} 15 40 }
16 41
return timeList 17 42 return timeList
} 18 43 }
19 44
fun getAllLatitude(): ArrayList<MessageData?> { 20 45 fun getAllLatitude(): ArrayList<MessageData?> {
val latitudeList = arrayListOf<MessageData?>() 21 46 val latitudeList = arrayListOf<MessageData?>()
messages.forEach { 22 47 messages.forEach {
latitudeList.add(it.value.latitude) 23 48 latitudeList.add(it.value.latitude)
} 24 49 }
25 50
return latitudeList 26 51 return latitudeList
} 27 52 }
28 53
fun getAllLongitude(): ArrayList<MessageData?> { 29 54 fun getAllLongitude(): ArrayList<MessageData?> {
val longitudeList = arrayListOf<MessageData?>() 30 55 val longitudeList = arrayListOf<MessageData?>()
messages.forEach { 31 56 messages.forEach {
longitudeList.add(it.value.longitude) 32 57 longitudeList.add(it.value.longitude)
} 33 58 }
34 59
return longitudeList 35 60 return longitudeList
} 36 61 }
37 62
fun getAllSpeedOverGround(): ArrayList<MessageData?> { 38 63 fun getAllSpeedOverGround(): ArrayList<MessageData?> {
val speedOverGroundList = arrayListOf<MessageData?>() 39 64 val speedOverGroundList = arrayListOf<MessageData?>()
messages.forEach { 40 65 messages.forEach {
speedOverGroundList.add(it.value.speedOverGround) 41 66 speedOverGroundList.add(it.value.speedOverGround)
} 42 67 }
43 68
return speedOverGroundList 44 69 return speedOverGroundList
} 45 70 }
46 71
fun getAllCourseOverGround(): ArrayList<MessageData?> { 47 72 fun getAllCourseOverGround(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 48 73 val res = arrayListOf<MessageData?>()
messages.forEach { 49 74 messages.forEach {
res.add(it.value.courseOverGround) 50 75 res.add(it.value.courseOverGround)
} 51 76 }
52 77
return res 53 78 return res
} 54 79 }
55 80
fun getAllHeading(): ArrayList<MessageData?> { 56 81 fun getAllHeading(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 57 82 val res = arrayListOf<MessageData?>()
messages.forEach { 58 83 messages.forEach {
res.add(it.value.heading) 59 84 res.add(it.value.heading)
} 60 85 }
61 86
return res 62 87 return res
} 63 88 }
64 89
fun getAllVesselName(): ArrayList<MessageData?> { 65 90 fun getAllVesselName(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 66 91 val res = arrayListOf<MessageData?>()
messages.forEach { 67 92 messages.forEach {
res.add(it.value.vesselName) 68 93 res.add(it.value.vesselName)
} 69 94 }
return res 70 95 return res
} 71 96 }
72 97
fun getAllIMO(): ArrayList<MessageData?> { 73 98 fun getAllIMO(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 74 99 val res = arrayListOf<MessageData?>()
messages.forEach { 75 100 messages.forEach {
res.add(it.value.imo) 76 101 res.add(it.value.imo)
} 77 102 }
return res 78 103 return res
} 79 104 }
80 105
fun getAllCallSign(): ArrayList<MessageData?> { 81 106 fun getAllCallSign(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 82 107 val res = arrayListOf<MessageData?>()
messages.forEach { 83 108 messages.forEach {
res.add(it.value.callSign) 84 109 res.add(it.value.callSign)
} 85 110 }
return res 86 111 return res
} 87 112 }
88 113
fun getAllVesselType(): ArrayList<MessageData?> { 89 114 fun getAllVesselType(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 90 115 val res = arrayListOf<MessageData?>()
messages.forEach { 91 116 messages.forEach {
res.add(it.value.vesselType) 92 117 res.add(it.value.vesselType)
} 93 118 }
return res 94 119 return res
} 95 120 }
96 121
fun getAllStatus(): ArrayList<MessageData?> { 97 122 fun getAllStatus(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 98 123 val res = arrayListOf<MessageData?>()
messages.forEach { 99 124 messages.forEach {
res.add(it.value.status) 100 125 res.add(it.value.status)
} 101 126 }
return res 102 127 return res
} 103 128 }
104 129
fun getAllLength(): ArrayList<MessageData?> { 105 130 fun getAllLength(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 106 131 val res = arrayListOf<MessageData?>()
messages.forEach { 107 132 messages.forEach {
res.add(it.value.length) 108 133 res.add(it.value.length)
} 109 134 }
return res 110 135 return res
} 111 136 }
112 137
fun getAllWidth(): ArrayList<MessageData?> { 113 138 fun getAllWidth(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 114 139 val res = arrayListOf<MessageData?>()
messages.forEach { 115 140 messages.forEach {
res.add(it.value.width) 116 141 res.add(it.value.width)
} 117 142 }
return res 118 143 return res
src/main/kotlin/application/model/VesselGenerator.kt View file @ 3b26be8
package application.model 1 1 package application.model
2 2
import java.io.File 3 3 import java.io.File
4 import java.time.ZoneOffset
import java.util.* 4 5 import java.util.*
import kotlin.collections.ArrayList 5
6 6
fun createVesselCollection(file: File) : SortedMap<String, Vessel> { 7 7 fun createVesselCollection(file: File): SortedMap<String, Vessel> {
val messages : ArrayList<Message> = arrayListOf() 8 8 val messages: ArrayList<Message> = arrayListOf()
val vessels: SortedMap<String, Vessel> = sortedMapOf() 9 9 val vessels: SortedMap<String, Vessel> = sortedMapOf()
10 var maxTime: Long = 0
11 var minTime: Long = Long.MAX_VALUE
10 12
file.forEachLine { 11 13 file.forEachLine {
val arrayMessage = it.split(",") 12 14 val arrayMessage = it.split(",")
if (arrayMessage[0].toIntOrNull() !== null) { 13 15 if (arrayMessage[0].toIntOrNull() !== null) {
val message = Message(arrayMessage) 14 16 val message = Message(arrayMessage)
messages.add(message) 15 17 messages.add(message)
if (!vessels.containsKey(message.mmsi.value)){ 16 18 if (!vessels.containsKey(message.mmsi.value)) {
vessels[message.mmsi.value] = Vessel(message.mmsi.value!!) 17 19 vessels[message.mmsi.value] = Vessel(message.mmsi.value!!)
} 18 20 }
vessels[message.mmsi.value]?.messages?.set(message.time.value, message) 19 21 val time = message.time.value.toEpochSecond(ZoneOffset.UTC)
22 vessels[message.mmsi.value]?.messages?.set(time, message)
23 if (time > maxTime) {
24 maxTime = time
25 }
26 if (time < minTime){
27 minTime = time
28 }
} 20 29 }
21
} 22 30 }
31
32 Vessel.maxTime = maxTime
33 Vessel.minTime = minTime
23 34
return vessels 24 35 return vessels
src/main/kotlin/map/MapDisplayer.kt View file @ 3b26be8
package map 1 1 package map
2 2
import application.model.observableVessel 3 3 import application.model.observableVessel
4 4
fun clearMap(map: LeafletMapView) { 5 5 fun clearMap(map: LeafletMapView) {
clearMapCanvas(map) 6 6 clearMapCanvas(map)
clearMapCluster(map) 7 7 clearMapCluster(map)
clearHeatMap(map) 8 8 clearHeatMap(map)
} 9 9 }
10 10
fun clearMapCluster(map: LeafletMapView) { 11 11 fun clearMapCluster(map: LeafletMapView) {
map.execScript( 12 12 map.execScript(
""" 13 13 """
|myMap.removeLayer(markerClusters); 14 14 |myMap.removeLayer(markerClusters);
|var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10}); 15 15 |var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10});
""".trimMargin() 16 16 """.trimMargin()
) 17 17 )
} 18 18 }
19 19
fun clearMapCanvas(map: LeafletMapView) { 20 20 fun clearMapCanvas(map: LeafletMapView) {
map.execScript( 21 21 map.execScript(
""" 22 22 """
|myRenderer.removeFrom(myMap); 23 23 |myRenderer.removeFrom(myMap);
|var myRenderer = L.canvas({ padding: 0.5 }); 24 24 |var myRenderer = L.canvas({ padding: 0.5 });
""".trimMargin() 25 25 """.trimMargin()
) 26 26 )
} 27 27 }
28 28
fun clearHeatMap(map: LeafletMapView) { 29 29 fun clearHeatMap(map: LeafletMapView) {
map.execScript( 30 30 map.execScript(
""" 31 31 """
|heatLayer.removeFrom(myMap); 32 32 |heatLayer.removeFrom(myMap);
|var heatLayer = L.heatLayer([]).addTo(myMap); 33 33 |var heatLayer = L.heatLayer([]).addTo(myMap);
""".trimMargin() 34 34 """.trimMargin()
) 35 35 )
} 36 36 }
37 37
fun displayAllMessageOnMap(map: LeafletMapView) { 38 38 fun displayAllMessageOnMap(map: LeafletMapView) {
clearMap(map) 39 39 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 40 40 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 41 41 value.messages.forEach { (_, message) ->
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") 42 42 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)")
} 43 43 }
} 44 44 }
} 45 45 }
46 46
fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) { 47 47 fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) {
clearMap(map) 48 48 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 49 49 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 50 50 value.messages.forEach { (_, message) ->
if (selectedMMSI == message.mmsi.value) { 51 51 if (selectedMMSI == message.mmsi.value) {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap)") 52 52 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap)")
} else { 53 53 } else {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") 54 54 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)")
} 55 55 }
} 56 56 }
} 57 57 }
} 58 58 }
59 59
fun displayClusterMessageOnMap(map: LeafletMapView) { 60 60 fun displayClusterMessageOnMap(map: LeafletMapView) {
clearMap(map) 61 61 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 62 62 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 63 63 value.messages.forEach { (_, message) ->
map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") 64 64 map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));")
} 65 65 }
} 66 66 }
map.execScript("myMap.addLayer(markerClusters);") 67 67 map.execScript("myMap.addLayer(markerClusters);")
} 68 68 }
69 69
70 fun displayTargetedVessels(map: LeafletMapView) {
71 clearMap(map)
72 observableVessel.vessels.forEach { (_, value) ->
73 val message = value.messageToDisplay ?: return@forEach
74 map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));")
75 }
76 map.execScript("myMap.addLayer(markerClusters);")
77 }
78
fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) { 70 79 fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) {
clearMap(map) 71 80 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 72 81 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 73 82 value.messages.forEach { (_, message) ->
if (selectedMMSI == message.mmsi.value) { 74 83 if (selectedMMSI == message.mmsi.value) {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") 75 84 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);")
} else { 76 85 } else {
map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") 77 86 map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));")
} 78 87 }
} 79 88 }
} 80 89 }
map.execScript("myMap.addLayer(markerClusters);") 81 90 map.execScript("myMap.addLayer(markerClusters);")
} 82 91 }
83 92
fun displayHeatMapOnMap(map: LeafletMapView) { 84 93 fun displayHeatMapOnMap(map: LeafletMapView) {
clearMap(map) 85 94 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 86 95 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 87 96 value.messages.forEach { (_, message) ->
map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") 88 97 map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);")
} 89 98 }
} 90 99 }
} 91 100 }
92 101
fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) { 93 102 fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) {
clearMap(map) 94 103 clearMap(map)
src/main/resources/gui/mapPanel.fxml View file @ 3b26be8
<?xml version="1.0" encoding="UTF-8"?> 1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2
<?import javafx.scene.layout.StackPane?> 3 3 <?import javafx.scene.layout.*?>
4 4
<StackPane prefHeight="150.0" prefWidth="200.0" xmlns="http://javafx.com/javafx" 5 5 <VBox prefHeight="150.0" prefWidth="371.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller.MapPanelController">
xmlns:fx="http://javafx.com/fxml" 6 6 <StackPane fx:id="map" />
fx:controller="application.controller.MapPanelController" 7 7 <fx:include source="timePanel.fxml" />
fx:id="map"/> 8 8 </VBox>
9
src/main/resources/gui/timePanel.fxml View file @ 3b26be8
File was created 1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <?import javafx.geometry.*?>
4 <?import javafx.scene.control.*?>
5 <?import javafx.scene.layout.*?>
6
7 <HBox alignment="CENTER" prefHeight="65.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller.TimePanel">
8 <children>
9 <Button fx:id="timePlay" alignment="CENTER" mnemonicParsing="false" text="Play">
10 <HBox.margin>
11 <Insets left="5.0" right="5.0" />
12 </HBox.margin></Button>
13 <Button fx:id="timeStop" mnemonicParsing="false" text="Stop">
14 <HBox.margin>
15 <Insets left="5.0" right="5.0" />
16 </HBox.margin></Button>
17 <Slider fx:id="timeSlider">
18 <HBox.margin>
19 <Insets left="5.0" right="5.0" />
20 </HBox.margin></Slider>