Commit 78935bd622fe4fc1337b6cb6f8dc73d3cb031477
1 parent
3b26be8f99
Exists in
master
and in
1 other branch
slider bind to all type of map
Showing 7 changed files with 104 additions and 47 deletions Side-by-side Diff
- src/main/kotlin/application/controller/MapPanelController.kt
 - src/main/kotlin/application/controller/TimePanel.kt
 - src/main/kotlin/application/controller/VesselListPanelController.kt
 - src/main/kotlin/application/model/Vessel.kt
 - src/main/kotlin/map/LeafletMapView.kt
 - src/main/kotlin/map/MapDisplayer.kt
 - src/main/resources/gui/timePanel.fxml
 
src/main/kotlin/application/controller/MapPanelController.kt
View file @
78935bd
| ... | ... | @@ -24,12 +24,6 @@ | 
| 24 | 24 | setStateListener() | 
| 25 | 25 | observableCurrentTime() | 
| 26 | 26 | |
| 27 | - /*val completeFutureMap: CompletableFuture<Worker.State> = mapView.displayMap(MapConfig()) | |
| 28 | - completeFutureMap.whenComplete{ | |
| 29 | - workerState, _ -> | |
| 30 | - if (workerState == Worker.State.SUCCEEDED) { | |
| 31 | - } | |
| 32 | - }*/ | |
| 33 | 27 | map.children.add(mapView) | 
| 34 | 28 | map.children | 
| 35 | 29 | } | 
| 36 | 30 | |
| 37 | 31 | |
| ... | ... | @@ -47,16 +41,24 @@ | 
| 47 | 41 | } | 
| 48 | 42 | |
| 49 | 43 | private fun observableCurrentTime() { | 
| 50 | - observableCurrentTime.listeners.add(object : CurrentTime{ | |
| 44 | + observableCurrentTime.listeners.add(object : CurrentTime { | |
| 51 | 45 | override fun onValueChanged(newValue: Int) { | 
| 52 | - updateMap() | |
| 46 | + if (observableSelectedVessel.vessel.mmsi != null) { | |
| 47 | + updateMap(observableSelectedVessel.vessel.mmsi!!) | |
| 48 | + } else { | |
| 49 | + updateMap() | |
| 50 | + } | |
| 53 | 51 | } | 
| 54 | 52 | }) | 
| 55 | 53 | } | 
| 56 | 54 | |
| 57 | 55 | private fun updateMap() { | 
| 58 | - if (observableIsReplayState.value){ | |
| 59 | - displayTargetedVessels(mapView) | |
| 56 | + if (observableIsReplayState.value) { | |
| 57 | + when (observableMapState.state) { | |
| 58 | + ALL_MESSAGES -> displayTimedAllMessageOnMap(mapView) | |
| 59 | + CLUSTERED_MESSAGES -> displayTimedClusterMessageOnMap(mapView) | |
| 60 | + HEAT_MAP -> displayTimedHeatMapOnMap(mapView) | |
| 61 | + } | |
| 60 | 62 | } else { | 
| 61 | 63 | when (observableMapState.state) { | 
| 62 | 64 | ALL_MESSAGES -> displayAllMessageOnMap(mapView) | 
| ... | ... | @@ -67,10 +69,18 @@ | 
| 67 | 69 | } | 
| 68 | 70 | |
| 69 | 71 | private fun updateMap(selectedMMSI: String) { | 
| 70 | - when (observableMapState.state) { | |
| 71 | - ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI) | |
| 72 | - CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI) | |
| 73 | - HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI) | |
| 72 | + if (observableIsReplayState.value) { | |
| 73 | + when (observableMapState.state) { | |
| 74 | + ALL_MESSAGES -> displayTimedAllMessageOnMap(mapView, selectedMMSI) | |
| 75 | + CLUSTERED_MESSAGES -> displayTimedClusterMessageOnMap(mapView, selectedMMSI) | |
| 76 | + HEAT_MAP -> displayTimedHeatMapOnMap(mapView, selectedMMSI) | |
| 77 | + } | |
| 78 | + } else { | |
| 79 | + when (observableMapState.state) { | |
| 80 | + ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI) | |
| 81 | + CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI) | |
| 82 | + HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI) | |
| 83 | + } | |
| 74 | 84 | } | 
| 75 | 85 | } | 
| 76 | 86 | |
| 77 | 87 | |
| 78 | 88 | |
| ... | ... | @@ -85,15 +95,13 @@ | 
| 85 | 95 | private fun setObservableSelectedVesselListener() { | 
| 86 | 96 | observableSelectedVessel.listeners.add(object : SelectedVesselListener { | 
| 87 | 97 | override fun onValueChanged(newValue: Vessel) { | 
| 88 | - if (newValue.mmsi != null){ | |
| 98 | + if (newValue.mmsi != null) { | |
| 89 | 99 | updateMap(newValue.mmsi) | 
| 90 | - }else { | |
| 100 | + } else { | |
| 91 | 101 | updateMap() | 
| 92 | 102 | } | 
| 93 | 103 | } | 
| 94 | 104 | }) | 
| 95 | 105 | } | 
| 96 | - | |
| 97 | - | |
| 98 | 106 | } | 
src/main/kotlin/application/controller/TimePanel.kt
View file @
78935bd
| ... | ... | @@ -29,6 +29,8 @@ | 
| 29 | 29 | } | 
| 30 | 30 | |
| 31 | 31 | private fun setSliderMinMax() { | 
| 32 | + timeSlider.min = 0.0 | |
| 33 | + timeSlider.max = 0.0 | |
| 32 | 34 | observableVessel.listeners.add(object : MessageListener{ | 
| 33 | 35 | override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { | 
| 34 | 36 | timeSlider.max = Vessel.maxTime.toDouble() | 
src/main/kotlin/application/controller/VesselListPanelController.kt
View file @
78935bd
| ... | ... | @@ -6,10 +6,12 @@ | 
| 6 | 6 | import application.model.observableVessel | 
| 7 | 7 | import javafx.collections.FXCollections | 
| 8 | 8 | import javafx.collections.ObservableList | 
| 9 | -import javafx.event.EventHandler | |
| 10 | 9 | import javafx.fxml.FXML | 
| 11 | 10 | import javafx.fxml.Initializable | 
| 12 | -import javafx.scene.control.* | |
| 11 | +import javafx.scene.control.ListCell | |
| 12 | +import javafx.scene.control.ListView | |
| 13 | +import javafx.scene.control.MultipleSelectionModel | |
| 14 | +import javafx.scene.control.SelectionMode | |
| 13 | 15 | import javafx.scene.input.MouseEvent | 
| 14 | 16 | import java.net.URL | 
| 15 | 17 | import java.util.* | 
src/main/kotlin/application/model/Vessel.kt
View file @
78935bd
| ... | ... | @@ -7,32 +7,11 @@ | 
| 7 | 7 | val messages: SortedMap<Long, Message> = sortedMapOf() | 
| 8 | 8 | var messageToDisplay: Message? = null | 
| 9 | 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 } | |
| 10 | + field = | |
| 11 | + messages.asSequence().map { it }.firstOrNull { observableCurrentTime.value < it.key }.let { it?.value } | |
| 17 | 12 | return field | 
| 18 | 13 | } | 
| 19 | 14 | |
| 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 | - | |
| 36 | 15 | fun getAllTime(): ArrayList<MessageData?> { | 
| 37 | 16 | val timeList = arrayListOf<MessageData?>() | 
| 38 | 17 | messages.forEach { | 
| ... | ... | @@ -159,7 +138,7 @@ | 
| 159 | 138 | return res | 
| 160 | 139 | } | 
| 161 | 140 | |
| 162 | - companion object{ | |
| 141 | + companion object { | |
| 163 | 142 | var maxTime: Long = 0 | 
| 164 | 143 | var minTime: Long = 0 | 
| 165 | 144 | } | 
src/main/kotlin/map/LeafletMapView.kt
View file @
78935bd
| ... | ... | @@ -93,6 +93,7 @@ | 
| 93 | 93 | | layers: [layer1] | 
| 94 | 94 | |}); | 
| 95 | 95 | |L.control.scale().addTo(myMap); | 
| 96 | + |var markers = [] | |
| 96 | 97 | |var myRenderer = L.canvas({ padding: 0.5 }); | 
| 97 | 98 | |var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10}); | 
| 98 | 99 | |var heatLayer = L.heatLayer([]).addTo(myMap);""".trimMargin() | 
src/main/kotlin/map/MapDisplayer.kt
View file @
78935bd
| ... | ... | @@ -6,6 +6,7 @@ | 
| 6 | 6 | clearMapCanvas(map) | 
| 7 | 7 | clearMapCluster(map) | 
| 8 | 8 | clearHeatMap(map) | 
| 9 | + clearMarker(map) | |
| 9 | 10 | } | 
| 10 | 11 | |
| 11 | 12 | fun clearMapCluster(map: LeafletMapView) { | 
| ... | ... | @@ -35,6 +36,17 @@ | 
| 35 | 36 | ) | 
| 36 | 37 | } | 
| 37 | 38 | |
| 39 | +fun clearMarker(map: LeafletMapView) { | |
| 40 | + map.execScript( | |
| 41 | + """ | |
| 42 | + |for(var i = 0; i < markers.length; i++){ | |
| 43 | + |myMap.removeLayer(markers[i]); | |
| 44 | + |} | |
| 45 | + |markers = [] | |
| 46 | + """.trimMargin() | |
| 47 | + ) | |
| 48 | +} | |
| 49 | + | |
| 38 | 50 | fun displayAllMessageOnMap(map: LeafletMapView) { | 
| 39 | 51 | clearMap(map) | 
| 40 | 52 | observableVessel.vessels.forEach { (_, value) -> | 
| ... | ... | @@ -44,6 +56,14 @@ | 
| 44 | 56 | } | 
| 45 | 57 | } | 
| 46 | 58 | |
| 59 | +fun displayTimedAllMessageOnMap(map: LeafletMapView) { | |
| 60 | + clearMap(map) | |
| 61 | + observableVessel.vessels.forEach { (_, value) -> | |
| 62 | + val message = value.messageToDisplay ?: return@forEach | |
| 63 | + map.execScript("markers.push(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap))") | |
| 64 | + } | |
| 65 | +} | |
| 66 | + | |
| 47 | 67 | fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) { | 
| 48 | 68 | clearMap(map) | 
| 49 | 69 | observableVessel.vessels.forEach { (_, value) -> | 
| ... | ... | @@ -57,6 +77,18 @@ | 
| 57 | 77 | } | 
| 58 | 78 | } | 
| 59 | 79 | |
| 80 | +fun displayTimedAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) { | |
| 81 | + clearMap(map) | |
| 82 | + observableVessel.vessels.forEach { (_, value) -> | |
| 83 | + val message = value.messageToDisplay ?: return@forEach | |
| 84 | + if (selectedMMSI == message.mmsi.value) { | |
| 85 | + map.execScript("markers.push(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap))") | |
| 86 | + } else { | |
| 87 | + map.execScript("markers.push(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap))") | |
| 88 | + } | |
| 89 | + } | |
| 90 | +} | |
| 91 | + | |
| 60 | 92 | fun displayClusterMessageOnMap(map: LeafletMapView) { | 
| 61 | 93 | clearMap(map) | 
| 62 | 94 | observableVessel.vessels.forEach { (_, value) -> | 
| 63 | 95 | |
| ... | ... | @@ -67,11 +99,11 @@ | 
| 67 | 99 | map.execScript("myMap.addLayer(markerClusters);") | 
| 68 | 100 | } | 
| 69 | 101 | |
| 70 | -fun displayTargetedVessels(map: LeafletMapView) { | |
| 102 | +fun displayTimedClusterMessageOnMap(map: LeafletMapView) { | |
| 71 | 103 | clearMap(map) | 
| 72 | 104 | observableVessel.vessels.forEach { (_, value) -> | 
| 73 | 105 | 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()}'}));") | |
| 106 | + map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {radius: 0.01, color: '#${message.getHexColorStroke()}'}));") | |
| 75 | 107 | } | 
| 76 | 108 | map.execScript("myMap.addLayer(markerClusters);") | 
| 77 | 109 | } | 
| ... | ... | @@ -90,6 +122,19 @@ | 
| 90 | 122 | map.execScript("myMap.addLayer(markerClusters);") | 
| 91 | 123 | } | 
| 92 | 124 | |
| 125 | +fun displayTimedClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) { | |
| 126 | + clearMap(map) | |
| 127 | + observableVessel.vessels.forEach { (_, value) -> | |
| 128 | + val message = value.messageToDisplay ?: return@forEach | |
| 129 | + if (selectedMMSI == message.mmsi.value) { | |
| 130 | + map.execScript("markers.push(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {radius: 2, color: '#ff4040'}).addTo(myMap));") | |
| 131 | + } else { | |
| 132 | + map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {radius: 0.01, color: '#${message.getHexColorStroke()}'}));") | |
| 133 | + } | |
| 134 | + } | |
| 135 | + map.execScript("myMap.addLayer(markerClusters);") | |
| 136 | +} | |
| 137 | + | |
| 93 | 138 | fun displayHeatMapOnMap(map: LeafletMapView) { | 
| 94 | 139 | clearMap(map) | 
| 95 | 140 | observableVessel.vessels.forEach { (_, value) -> | 
| ... | ... | @@ -99,6 +144,14 @@ | 
| 99 | 144 | } | 
| 100 | 145 | } | 
| 101 | 146 | |
| 147 | +fun displayTimedHeatMapOnMap(map: LeafletMapView) { | |
| 148 | + clearMap(map) | |
| 149 | + observableVessel.vessels.forEach { (_, value) -> | |
| 150 | + val message = value.messageToDisplay ?: return@forEach | |
| 151 | + map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") | |
| 152 | + } | |
| 153 | +} | |
| 154 | + | |
| 102 | 155 | fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) { | 
| 103 | 156 | clearMap(map) | 
| 104 | 157 | observableVessel.vessels.forEach { (_, value) -> | 
| ... | ... | @@ -111,5 +164,17 @@ | 
| 111 | 164 | } | 
| 112 | 165 | } | 
| 113 | 166 | map.execScript("myMap.addLayer(markerClusters);") | 
| 167 | +} | |
| 168 | + | |
| 169 | +fun displayTimedHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) { | |
| 170 | + clearMap(map) | |
| 171 | + observableVessel.vessels.forEach { (_, value) -> | |
| 172 | + val message = value.messageToDisplay ?: return@forEach | |
| 173 | + if (selectedMMSI == message.mmsi.value) { | |
| 174 | + map.execScript("markers.push(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {radius: 2, color: '#ff4040'}).addTo(myMap));") | |
| 175 | + } else { | |
| 176 | + map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") | |
| 177 | + } | |
| 178 | + } | |
| 114 | 179 | } | 
src/main/resources/gui/timePanel.fxml
View file @
78935bd
| ... | ... | @@ -14,7 +14,7 @@ | 
| 14 | 14 | <HBox.margin> | 
| 15 | 15 | <Insets left="5.0" right="5.0" /> | 
| 16 | 16 | </HBox.margin></Button> | 
| 17 | - <Slider fx:id="timeSlider"> | |
| 17 | + <Slider fx:id="timeSlider" prefHeight="14.0" prefWidth="475.0"> | |
| 18 | 18 | <HBox.margin> | 
| 19 | 19 | <Insets left="5.0" right="5.0" /> | 
| 20 | 20 | </HBox.margin></Slider> |