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 Side-by-side Diff

src/main/kotlin/application/controller/DataPanelController.kt View file @ 3b26be8
... ... @@ -103,7 +103,7 @@
103 103 }
104 104  
105 105 config.plotTitle = ""
106   - config.setxAxisTitle("Date")
  106 + config.setxAxisTitle("Time (s)")
107 107 config.setyAxisTitle(newValue.first)
108 108 dataViewer.resetPlot()
109 109 plotData.allTraces.clear()
src/main/kotlin/application/controller/MapPanelController.kt View file @ 3b26be8
1 1 package application.controller
2 2  
3 3 import application.model.*
4   -import application.model.State.*
  4 +import application.model.MapState.*
5 5 import javafx.fxml.FXML
6 6 import javafx.fxml.Initializable
7 7 import javafx.scene.layout.StackPane
... ... @@ -22,6 +22,8 @@
22 22 setObservableVesselListener()
23 23 setObservableSelectedVesselListener()
24 24 setStateListener()
  25 + observableCurrentTime()
  26 +
25 27 /*val completeFutureMap: CompletableFuture<Worker.State> = mapView.displayMap(MapConfig())
26 28 completeFutureMap.whenComplete{
27 29 workerState, _ ->
... ... @@ -33,8 +35,8 @@
33 35 }
34 36  
35 37 private fun setStateListener() {
36   - observableState.listeners.add(object : StateListener {
37   - override fun onValueChanged(newValue: State) {
  38 + observableMapState.listeners.add(object : StateListener {
  39 + override fun onValueChanged(newValue: MapState) {
38 40 if (observableSelectedVessel.vessel.mmsi != null) {
39 41 updateMap(observableSelectedVessel.vessel.mmsi!!)
40 42 } else {
41 43  
42 44  
... ... @@ -44,16 +46,28 @@
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 +
47 57 private fun updateMap() {
48   - when (observableState.state) {
49   - ALL_MESSAGES -> displayAllMessageOnMap(mapView)
50   - CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView)
51   - HEAT_MAP -> displayHeatMapOnMap(mapView)
  58 + if (observableIsReplayState.value){
  59 + displayTargetedVessels(mapView)
  60 + } else {
  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  
55 69 private fun updateMap(selectedMMSI: String) {
56   - when (observableState.state) {
  70 + when (observableMapState.state) {
57 71 ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI)
58 72 CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI)
59 73 HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI)
src/main/kotlin/application/controller/MenuBarController.kt View file @ 3b26be8
1 1 package application.controller
2 2  
3   -import application.model.State.*
  3 +import application.model.MapState.*
4 4 import application.model.createVesselCollection
5   -import application.model.observableState
  5 +import application.model.observableMapState
6 6 import application.model.observableVessel
7 7 import javafx.event.EventHandler
8 8 import javafx.fxml.FXML
... ... @@ -39,7 +39,7 @@
39 39 setOnActionAllMessageButton()
40 40 setOnActionClusteredMessageButton()
41 41 setOnActionHeatMapButton()
42   - observableState.state = CLUSTERED_MESSAGES
  42 + observableMapState.state = CLUSTERED_MESSAGES
43 43 allMessages.isSelected = false
44 44 clusteredMessage.isSelected = true
45 45 heatMap.isSelected = false
... ... @@ -71,7 +71,7 @@
71 71  
72 72 private fun setOnActionAllMessageButton() {
73 73 allMessages.onAction = EventHandler {
74   - observableState.state = ALL_MESSAGES
  74 + observableMapState.state = ALL_MESSAGES
75 75 allMessages.isSelected = true
76 76 clusteredMessage.isSelected = false
77 77 heatMap.isSelected = false
... ... @@ -80,7 +80,7 @@
80 80  
81 81 private fun setOnActionClusteredMessageButton() {
82 82 clusteredMessage.onAction = EventHandler {
83   - observableState.state = CLUSTERED_MESSAGES
  83 + observableMapState.state = CLUSTERED_MESSAGES
84 84 heatMap.isSelected = false
85 85 allMessages.isSelected = false
86 86 clusteredMessage.isSelected = true
... ... @@ -89,7 +89,7 @@
89 89  
90 90 private fun setOnActionHeatMapButton() {
91 91 heatMap.onAction = EventHandler {
92   - observableState.state = HEAT_MAP
  92 + observableMapState.state = HEAT_MAP
93 93 heatMap.isSelected = true
94 94 clusteredMessage.isSelected = false
95 95 allMessages.isSelected = false
src/main/kotlin/application/controller/TimePanel.kt View file @ 3b26be8
  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>) {
  34 + timeSlider.max = Vessel.maxTime.toDouble()
  35 + timeSlider.min = Vessel.minTime.toDouble()
  36 + }
  37 + })
  38 + }
  39 +
  40 + private fun setSliderListener() {
  41 + timeSlider.valueProperty().addListener { _, _, newValue ->
  42 + observableCurrentTime.value = newValue.toInt()
  43 + }
  44 + }
  45 +
  46 +}
src/main/kotlin/application/model/Context.kt View file @ 3b26be8
... ... @@ -4,5 +4,9 @@
4 4  
5 5 val observableSelectedVessel: ObservableSelectedVessel = ObservableSelectedVessel()
6 6  
7   -val observableState: ObservableState = ObservableState()
  7 +val observableMapState: ObservableMapState = ObservableMapState()
  8 +
  9 +val observableIsReplayState: ObservableReplayState = ObservableReplayState()
  10 +
  11 +val observableCurrentTime: ObservableCurrentTime = ObservableCurrentTime()
src/main/kotlin/application/model/CurrentTime.kt View file @ 3b26be8
  1 +package application.model
  2 +
  3 +interface CurrentTime {
  4 + fun onValueChanged(newValue: Int)
  5 +}
src/main/kotlin/application/model/MapState.kt View file @ 3b26be8
  1 +package application.model
  2 +
  3 +enum class MapState {
  4 + ALL_MESSAGES,
  5 + CLUSTERED_MESSAGES,
  6 + HEAT_MAP
  7 +}
src/main/kotlin/application/model/ObservableCurrentTime.kt View file @ 3b26be8
  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 + }
  16 + }
  17 + }
  18 + )
  19 +
  20 +}
src/main/kotlin/application/model/ObservableMapState.kt View file @ 3b26be8
  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 + }
  16 + }
  17 + )
  18 +}
src/main/kotlin/application/model/ObservableReplayState.kt View file @ 3b26be8
  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 + }
  16 + }
  17 + }
  18 + )
  19 +
  20 +}
src/main/kotlin/application/model/ObservableState.kt View file @ 3b26be8
1   -package application.model
2   -
3   -import kotlin.properties.Delegates
4   -
5   -class ObservableState {
6   - val listeners: MutableList<StateListener> = mutableListOf()
7   -
8   - var state: State by Delegates.observable(
9   - initialValue = State.CLUSTERED_MESSAGES,
10   - onChange = { _, _, new ->
11   - run {
12   - listeners.forEach {
13   - it.onValueChanged(new)
14   - }
15   - }
16   - }
17   - )
18   -}
src/main/kotlin/application/model/ReplayState.kt View file @ 3b26be8
  1 +package application.model
  2 +
  3 +interface ReplayState {
  4 + fun onValueChanged(newValue: Boolean)
  5 +
  6 +}
src/main/kotlin/application/model/State.kt View file @ 3b26be8
1   -package application.model
2   -
3   -enum class State {
4   - ALL_MESSAGES,
5   - CLUSTERED_MESSAGES,
6   - HEAT_MAP
7   -}
src/main/kotlin/application/model/StateListener.kt View file @ 3b26be8
1 1 package application.model
2 2  
3 3 interface StateListener {
4   - fun onValueChanged(newValue: State)
  4 + fun onValueChanged(newValue: MapState)
5 5 }
src/main/kotlin/application/model/Vessel.kt View file @ 3b26be8
1 1 package application.model
2 2  
3   -import java.time.LocalDateTime
4   -import java.time.ZoneOffset
5 3 import java.util.*
6 4  
7 5  
8 6 class Vessel(val mmsi: String?) {
9   - val messages: SortedMap<LocalDateTime, Message> = sortedMapOf()
  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 +
11 36 fun getAllTime(): ArrayList<MessageData?> {
12 37 val timeList = arrayListOf<MessageData?>()
13 38 messages.forEach {
... ... @@ -132,6 +157,11 @@
132 157 res.add(it.value.cargo)
133 158 }
134 159 return res
  160 + }
  161 +
  162 + companion object{
  163 + var maxTime: Long = 0
  164 + var minTime: Long = 0
135 165 }
136 166  
137 167 }
src/main/kotlin/application/model/VesselGenerator.kt View file @ 3b26be8
1 1 package application.model
2 2  
3 3 import java.io.File
  4 +import java.time.ZoneOffset
4 5 import java.util.*
5   -import kotlin.collections.ArrayList
6 6  
7   -fun createVesselCollection(file: File) : SortedMap<String, Vessel> {
8   - val messages : ArrayList<Message> = arrayListOf()
  7 +fun createVesselCollection(file: File): SortedMap<String, Vessel> {
  8 + val messages: ArrayList<Message> = arrayListOf()
9 9 val vessels: SortedMap<String, Vessel> = sortedMapOf()
  10 + var maxTime: Long = 0
  11 + var minTime: Long = Long.MAX_VALUE
10 12  
11 13 file.forEachLine {
12 14 val arrayMessage = it.split(",")
13 15 if (arrayMessage[0].toIntOrNull() !== null) {
14 16 val message = Message(arrayMessage)
15 17 messages.add(message)
16   - if (!vessels.containsKey(message.mmsi.value)){
  18 + if (!vessels.containsKey(message.mmsi.value)) {
17 19 vessels[message.mmsi.value] = Vessel(message.mmsi.value!!)
18 20 }
19   - vessels[message.mmsi.value]?.messages?.set(message.time.value, message)
  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  
24 35 return vessels
25 36 }
src/main/kotlin/map/MapDisplayer.kt View file @ 3b26be8
... ... @@ -67,6 +67,15 @@
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 +
70 79 fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) {
71 80 clearMap(map)
72 81 observableVessel.vessels.forEach { (_, value) ->
src/main/resources/gui/mapPanel.fxml View file @ 3b26be8
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2  
3   -<?import javafx.scene.layout.StackPane?>
  3 +<?import javafx.scene.layout.*?>
4 4  
5   -<StackPane prefHeight="150.0" prefWidth="200.0" xmlns="http://javafx.com/javafx"
6   - xmlns:fx="http://javafx.com/fxml"
7   - fx:controller="application.controller.MapPanelController"
8   - fx:id="map"/>
  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">
  6 + <StackPane fx:id="map" />
  7 + <fx:include source="timePanel.fxml" />
  8 +</VBox>
src/main/resources/gui/timePanel.fxml View file @ 3b26be8
  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>
  21 + </children>
  22 +</HBox>