Commit 78935bd622fe4fc1337b6cb6f8dc73d3cb031477

Authored by lsagona
1 parent 3b26be8f99
Exists in master and in 1 other branch dev

slider bind to all type of map

Showing 7 changed files with 104 additions and 47 deletions Inline Diff

src/main/kotlin/application/controller/MapPanelController.kt View file @ 78935bd
package application.controller 1 1 package application.controller
2 2
import application.model.* 3 3 import application.model.*
import application.model.MapState.* 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()
observableCurrentTime() 25 25 observableCurrentTime()
26 26
/*val completeFutureMap: CompletableFuture<Worker.State> = mapView.displayMap(MapConfig()) 27
completeFutureMap.whenComplete{ 28
workerState, _ -> 29
if (workerState == Worker.State.SUCCEEDED) { 30
} 31
}*/ 32
map.children.add(mapView) 33 27 map.children.add(mapView)
map.children 34 28 map.children
} 35 29 }
36 30
private fun setStateListener() { 37 31 private fun setStateListener() {
observableMapState.listeners.add(object : StateListener { 38 32 observableMapState.listeners.add(object : StateListener {
override fun onValueChanged(newValue: MapState) { 39 33 override fun onValueChanged(newValue: MapState) {
if (observableSelectedVessel.vessel.mmsi != null) { 40 34 if (observableSelectedVessel.vessel.mmsi != null) {
updateMap(observableSelectedVessel.vessel.mmsi!!) 41 35 updateMap(observableSelectedVessel.vessel.mmsi!!)
} else { 42 36 } else {
updateMap() 43 37 updateMap()
} 44 38 }
} 45 39 }
}) 46 40 })
} 47 41 }
48 42
private fun observableCurrentTime() { 49 43 private fun observableCurrentTime() {
observableCurrentTime.listeners.add(object : CurrentTime{ 50 44 observableCurrentTime.listeners.add(object : CurrentTime {
override fun onValueChanged(newValue: Int) { 51 45 override fun onValueChanged(newValue: Int) {
updateMap() 52 46 if (observableSelectedVessel.vessel.mmsi != null) {
47 updateMap(observableSelectedVessel.vessel.mmsi!!)
48 } else {
49 updateMap()
50 }
} 53 51 }
}) 54 52 })
} 55 53 }
56 54
private fun updateMap() { 57 55 private fun updateMap() {
if (observableIsReplayState.value){ 58 56 if (observableIsReplayState.value) {
displayTargetedVessels(mapView) 59 57 when (observableMapState.state) {
58 ALL_MESSAGES -> displayTimedAllMessageOnMap(mapView)
59 CLUSTERED_MESSAGES -> displayTimedClusterMessageOnMap(mapView)
60 HEAT_MAP -> displayTimedHeatMapOnMap(mapView)
61 }
} else { 60 62 } else {
when (observableMapState.state) { 61 63 when (observableMapState.state) {
ALL_MESSAGES -> displayAllMessageOnMap(mapView) 62 64 ALL_MESSAGES -> displayAllMessageOnMap(mapView)
CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView) 63 65 CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView)
HEAT_MAP -> displayHeatMapOnMap(mapView) 64 66 HEAT_MAP -> displayHeatMapOnMap(mapView)
} 65 67 }
} 66 68 }
} 67 69 }
68 70
private fun updateMap(selectedMMSI: String) { 69 71 private fun updateMap(selectedMMSI: String) {
when (observableMapState.state) { 70 72 if (observableIsReplayState.value) {
ALL_MESSAGES -> displayAllMessageOnMap(mapView, selectedMMSI) 71 73 when (observableMapState.state) {
CLUSTERED_MESSAGES -> displayClusterMessageOnMap(mapView, selectedMMSI) 72 74 ALL_MESSAGES -> displayTimedAllMessageOnMap(mapView, selectedMMSI)
HEAT_MAP -> displayHeatMapOnMap(mapView, selectedMMSI) 73 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
private fun setObservableVesselListener() { 77 87 private fun setObservableVesselListener() {
observableVessel.listeners.add(object : MessageListener { 78 88 observableVessel.listeners.add(object : MessageListener {
override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { 79 89 override fun onValueChanged(newValue: MutableMap<String?, Vessel>) {
updateMap() 80 90 updateMap()
} 81 91 }
}) 82 92 })
} 83 93 }
84 94
private fun setObservableSelectedVesselListener() { 85 95 private fun setObservableSelectedVesselListener() {
observableSelectedVessel.listeners.add(object : SelectedVesselListener { 86 96 observableSelectedVessel.listeners.add(object : SelectedVesselListener {
override fun onValueChanged(newValue: Vessel) { 87 97 override fun onValueChanged(newValue: Vessel) {
if (newValue.mmsi != null){ 88 98 if (newValue.mmsi != null) {
updateMap(newValue.mmsi) 89 99 updateMap(newValue.mmsi)
}else { 90 100 } else {
updateMap() 91 101 updateMap()
} 92 102 }
} 93 103 }
src/main/kotlin/application/controller/TimePanel.kt View file @ 78935bd
package application.controller 1 1 package application.controller
2 2
import application.model.* 3 3 import application.model.*
import javafx.fxml.FXML 4 4 import javafx.fxml.FXML
import javafx.fxml.Initializable 5 5 import javafx.fxml.Initializable
import javafx.scene.control.Button 6 6 import javafx.scene.control.Button
import javafx.scene.control.Slider 7 7 import javafx.scene.control.Slider
import java.net.URL 8 8 import java.net.URL
import java.util.* 9 9 import java.util.*
10 10
11 11
class TimePanel : Initializable { 12 12 class TimePanel : Initializable {
13 13
@FXML 14 14 @FXML
var timeSlider = Slider() 15 15 var timeSlider = Slider()
16 16
@FXML 17 17 @FXML
var timeStop = Button() 18 18 var timeStop = Button()
19 19
@FXML 20 20 @FXML
var timePlay = Button() 21 21 var timePlay = Button()
22 22
23 23
override fun initialize(location: URL?, resources: ResourceBundle?) { 24 24 override fun initialize(location: URL?, resources: ResourceBundle?) {
setSliderMinMax() 25 25 setSliderMinMax()
setSliderListener() 26 26 setSliderListener()
27 27
28 28
} 29 29 }
30 30
private fun setSliderMinMax() { 31 31 private fun setSliderMinMax() {
32 timeSlider.min = 0.0
33 timeSlider.max = 0.0
observableVessel.listeners.add(object : MessageListener{ 32 34 observableVessel.listeners.add(object : MessageListener{
override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { 33 35 override fun onValueChanged(newValue: MutableMap<String?, Vessel>) {
src/main/kotlin/application/controller/VesselListPanelController.kt View file @ 78935bd
package application.controller 1 1 package application.controller
2 2
import application.model.MessageListener 3 3 import application.model.MessageListener
import application.model.Vessel 4 4 import application.model.Vessel
import application.model.observableSelectedVessel 5 5 import application.model.observableSelectedVessel
import application.model.observableVessel 6 6 import application.model.observableVessel
import javafx.collections.FXCollections 7 7 import javafx.collections.FXCollections
import javafx.collections.ObservableList 8 8 import javafx.collections.ObservableList
import javafx.event.EventHandler 9
import javafx.fxml.FXML 10 9 import javafx.fxml.FXML
import javafx.fxml.Initializable 11 10 import javafx.fxml.Initializable
import javafx.scene.control.* 12 11 import javafx.scene.control.ListCell
12 import javafx.scene.control.ListView
13 import javafx.scene.control.MultipleSelectionModel
14 import javafx.scene.control.SelectionMode
import javafx.scene.input.MouseEvent 13 15 import javafx.scene.input.MouseEvent
import java.net.URL 14 16 import java.net.URL
import java.util.* 15 17 import java.util.*
16 18
17 19
class VesselListPanelController : Initializable, MessageListener { 18 20 class VesselListPanelController : Initializable, MessageListener {
@FXML 19 21 @FXML
var shipListView: ListView<String?> = ListView() 20 22 var shipListView: ListView<String?> = ListView()
21 23
private var shipList: ObservableList<String?> = FXCollections.observableArrayList() 22 24 private var shipList: ObservableList<String?> = FXCollections.observableArrayList()
23 25
override fun initialize(location: URL?, resources: ResourceBundle?) { 24 26 override fun initialize(location: URL?, resources: ResourceBundle?) {
25 27
26 28
shipListView.items = shipList 27 29 shipListView.items = shipList
observableVessel.listeners.add(this) 28 30 observableVessel.listeners.add(this)
shipListView.selectionModel.selectedItemProperty().addListener { _, _, newValue -> 29 31 shipListView.selectionModel.selectedItemProperty().addListener { _, _, newValue ->
if (newValue == null) { 30 32 if (newValue == null) {
observableSelectedVessel.vessel = Vessel(null) 31 33 observableSelectedVessel.vessel = Vessel(null)
} else { 32 34 } else {
observableSelectedVessel.vessel = observableVessel.vessels[newValue]!! 33 35 observableSelectedVessel.vessel = observableVessel.vessels[newValue]!!
} 34 36 }
} 35 37 }
setCellFactory() 36 38 setCellFactory()
} 37 39 }
38 40
override fun onValueChanged(newValue: MutableMap<String?, Vessel>) { 39 41 override fun onValueChanged(newValue: MutableMap<String?, Vessel>) {
shipList.clear() 40 42 shipList.clear()
shipList.addAll(newValue.keys) 41 43 shipList.addAll(newValue.keys)
} 42 44 }
43 45
private fun setCellFactory() { 44 46 private fun setCellFactory() {
val selectionModel: MultipleSelectionModel<String?>? = shipListView.selectionModel 45 47 val selectionModel: MultipleSelectionModel<String?>? = shipListView.selectionModel
selectionModel?.selectionMode = SelectionMode.SINGLE 46 48 selectionModel?.selectionMode = SelectionMode.SINGLE
shipListView.setCellFactory { 47 49 shipListView.setCellFactory {
val cell = ListCell<String?>() 48 50 val cell = ListCell<String?>()
cell.textProperty().bind(cell.itemProperty()) 49 51 cell.textProperty().bind(cell.itemProperty())
cell.addEventFilter(MouseEvent.MOUSE_PRESSED) { event: MouseEvent -> 50 52 cell.addEventFilter(MouseEvent.MOUSE_PRESSED) { event: MouseEvent ->
shipListView.requestFocus() 51 53 shipListView.requestFocus()
if (!cell.isEmpty) { 52 54 if (!cell.isEmpty) {
val index = cell.index 53 55 val index = cell.index
if (selectionModel!!.selectedIndices.contains(index)) { 54 56 if (selectionModel!!.selectedIndices.contains(index)) {
selectionModel.clearSelection() 55 57 selectionModel.clearSelection()
} else { 56 58 } else {
selectionModel.select(index) 57 59 selectionModel.select(index)
src/main/kotlin/application/model/Vessel.kt View file @ 78935bd
package application.model 1 1 package application.model
2 2
import java.util.* 3 3 import java.util.*
4 4
5 5
class Vessel(val mmsi: String?) { 6 6 class Vessel(val mmsi: String?) {
val messages: SortedMap<Long, Message> = sortedMapOf() 7 7 val messages: SortedMap<Long, Message> = sortedMapOf()
var messageToDisplay: Message? = null 8 8 var messageToDisplay: Message? = null
get() { 9 9 get() {
// messages.forEach { (key, value) -> 10 10 field =
// if(observableCurrentTime.value < key) { 11 11 messages.asSequence().map { it }.firstOrNull { observableCurrentTime.value < it.key }.let { it?.value }
// field = value 12
// return@forEach 13
// } 14
// } 15
field = messages.asSequence().map{ it }.firstOrNull {observableCurrentTime.value < it.key}.let { it?.value } 16
return field 17 12 return field
} 18 13 }
19 14
// val timesNormalized : SortedMap<Long, LocalDateTime> = sortedMapOf() 20
21
// fun getAllNormalizedDate(): SortedMap<Long, LocalDateTime> { 22
// var offset: Long? = null 23
// if(timesNormalized.size == 0){ 24
// messages.keys.forEach { 25
// val currentTime = it.toEpochSecond(ZoneOffset.UTC) 26
// if(offset == null){ 27
// offset = currentTime 28
// } 29
// timesNormalized[currentTime - offset!!]= it 30
// } 31
// } 32
// return timesNormalized 33
// } 34
35
fun getAllTime(): ArrayList<MessageData?> { 36 15 fun getAllTime(): ArrayList<MessageData?> {
val timeList = arrayListOf<MessageData?>() 37 16 val timeList = arrayListOf<MessageData?>()
messages.forEach { 38 17 messages.forEach {
timeList.add(it.value.time) 39 18 timeList.add(it.value.time)
} 40 19 }
41 20
return timeList 42 21 return timeList
} 43 22 }
44 23
fun getAllLatitude(): ArrayList<MessageData?> { 45 24 fun getAllLatitude(): ArrayList<MessageData?> {
val latitudeList = arrayListOf<MessageData?>() 46 25 val latitudeList = arrayListOf<MessageData?>()
messages.forEach { 47 26 messages.forEach {
latitudeList.add(it.value.latitude) 48 27 latitudeList.add(it.value.latitude)
} 49 28 }
50 29
return latitudeList 51 30 return latitudeList
} 52 31 }
53 32
fun getAllLongitude(): ArrayList<MessageData?> { 54 33 fun getAllLongitude(): ArrayList<MessageData?> {
val longitudeList = arrayListOf<MessageData?>() 55 34 val longitudeList = arrayListOf<MessageData?>()
messages.forEach { 56 35 messages.forEach {
longitudeList.add(it.value.longitude) 57 36 longitudeList.add(it.value.longitude)
} 58 37 }
59 38
return longitudeList 60 39 return longitudeList
} 61 40 }
62 41
fun getAllSpeedOverGround(): ArrayList<MessageData?> { 63 42 fun getAllSpeedOverGround(): ArrayList<MessageData?> {
val speedOverGroundList = arrayListOf<MessageData?>() 64 43 val speedOverGroundList = arrayListOf<MessageData?>()
messages.forEach { 65 44 messages.forEach {
speedOverGroundList.add(it.value.speedOverGround) 66 45 speedOverGroundList.add(it.value.speedOverGround)
} 67 46 }
68 47
return speedOverGroundList 69 48 return speedOverGroundList
} 70 49 }
71 50
fun getAllCourseOverGround(): ArrayList<MessageData?> { 72 51 fun getAllCourseOverGround(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 73 52 val res = arrayListOf<MessageData?>()
messages.forEach { 74 53 messages.forEach {
res.add(it.value.courseOverGround) 75 54 res.add(it.value.courseOverGround)
} 76 55 }
77 56
return res 78 57 return res
} 79 58 }
80 59
fun getAllHeading(): ArrayList<MessageData?> { 81 60 fun getAllHeading(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 82 61 val res = arrayListOf<MessageData?>()
messages.forEach { 83 62 messages.forEach {
res.add(it.value.heading) 84 63 res.add(it.value.heading)
} 85 64 }
86 65
return res 87 66 return res
} 88 67 }
89 68
fun getAllVesselName(): ArrayList<MessageData?> { 90 69 fun getAllVesselName(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 91 70 val res = arrayListOf<MessageData?>()
messages.forEach { 92 71 messages.forEach {
res.add(it.value.vesselName) 93 72 res.add(it.value.vesselName)
} 94 73 }
return res 95 74 return res
} 96 75 }
97 76
fun getAllIMO(): ArrayList<MessageData?> { 98 77 fun getAllIMO(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 99 78 val res = arrayListOf<MessageData?>()
messages.forEach { 100 79 messages.forEach {
res.add(it.value.imo) 101 80 res.add(it.value.imo)
} 102 81 }
return res 103 82 return res
} 104 83 }
105 84
fun getAllCallSign(): ArrayList<MessageData?> { 106 85 fun getAllCallSign(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 107 86 val res = arrayListOf<MessageData?>()
messages.forEach { 108 87 messages.forEach {
res.add(it.value.callSign) 109 88 res.add(it.value.callSign)
} 110 89 }
return res 111 90 return res
} 112 91 }
113 92
fun getAllVesselType(): ArrayList<MessageData?> { 114 93 fun getAllVesselType(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 115 94 val res = arrayListOf<MessageData?>()
messages.forEach { 116 95 messages.forEach {
res.add(it.value.vesselType) 117 96 res.add(it.value.vesselType)
} 118 97 }
return res 119 98 return res
} 120 99 }
121 100
fun getAllStatus(): ArrayList<MessageData?> { 122 101 fun getAllStatus(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 123 102 val res = arrayListOf<MessageData?>()
messages.forEach { 124 103 messages.forEach {
res.add(it.value.status) 125 104 res.add(it.value.status)
} 126 105 }
return res 127 106 return res
} 128 107 }
129 108
fun getAllLength(): ArrayList<MessageData?> { 130 109 fun getAllLength(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 131 110 val res = arrayListOf<MessageData?>()
messages.forEach { 132 111 messages.forEach {
res.add(it.value.length) 133 112 res.add(it.value.length)
} 134 113 }
return res 135 114 return res
} 136 115 }
137 116
fun getAllWidth(): ArrayList<MessageData?> { 138 117 fun getAllWidth(): ArrayList<MessageData?> {
val res = arrayListOf<MessageData?>() 139 118 val res = arrayListOf<MessageData?>()
messages.forEach { 140 119 messages.forEach {
res.add(it.value.width) 141 120 res.add(it.value.width)
} 142 121 }
src/main/kotlin/map/LeafletMapView.kt View file @ 78935bd
package map 1 1 package map
2 2
import javafx.concurrent.Worker 3 3 import javafx.concurrent.Worker
import javafx.scene.layout.StackPane 4 4 import javafx.scene.layout.StackPane
import javafx.scene.paint.Color 5 5 import javafx.scene.paint.Color
import javafx.scene.shape.Polygon 6 6 import javafx.scene.shape.Polygon
import javafx.scene.web.WebEngine 7 7 import javafx.scene.web.WebEngine
import javafx.scene.web.WebView 8 8 import javafx.scene.web.WebView
import map.events.* 9 9 import map.events.*
import netscape.javascript.JSObject 10 10 import netscape.javascript.JSObject
import java.io.ByteArrayOutputStream 11 11 import java.io.ByteArrayOutputStream
import java.io.File 12 12 import java.io.File
import java.io.IOException 13 13 import java.io.IOException
import java.net.URL 14 14 import java.net.URL
import java.util.* 15 15 import java.util.*
import java.util.concurrent.CompletableFuture 16 16 import java.util.concurrent.CompletableFuture
import javax.imageio.ImageIO 17 17 import javax.imageio.ImageIO
18 18
19 19
/** 20 20 /**
* JavaFX component for displaying OpenStreetMap based maps by using the Leaflet.js JavaScript library inside a WebView 21 21 * JavaFX component for displaying OpenStreetMap based maps by using the Leaflet.js JavaScript library inside a WebView
* browser component.<br/> 22 22 * browser component.<br/>
* This component can be embedded most easily by placing it inside a StackPane, the component uses then the size of the 23 23 * This component can be embedded most easily by placing it inside a StackPane, the component uses then the size of the
* parent automatically. 24 24 * parent automatically.
* 25 25 *
* @author Stefan Saring 26 26 * @author Stefan Saring
* @author Niklas Kellner 27 27 * @author Niklas Kellner
*/ 28 28 */
class LeafletMapView : StackPane() { 29 29 class LeafletMapView : StackPane() {
30 30
private val webView = WebView() 31 31 private val webView = WebView()
private val webEngine: WebEngine = webView.engine 32 32 private val webEngine: WebEngine = webView.engine
33 33
private var varNameSuffix: Int = 1 34 34 private var varNameSuffix: Int = 1
private val mapClickEvent = MapClickEventMaker() 35 35 private val mapClickEvent = MapClickEventMaker()
private val markerClickEvent = MarkerClickEventMaker() 36 36 private val markerClickEvent = MarkerClickEventMaker()
private val mapMoveEvent = MapMoveEventMaker() 37 37 private val mapMoveEvent = MapMoveEventMaker()
internal val zoomLimitSmallMarker = 8 38 38 internal val zoomLimitSmallMarker = 8
39 39
/** 40 40 /**
* Creates the LeafletMapView component, it does not show any map yet. 41 41 * Creates the LeafletMapView component, it does not show any map yet.
*/ 42 42 */
init { 43 43 init {
this.children.add(webView) 44 44 this.children.add(webView)
} 45 45 }
46 46
/** 47 47 /**
* Displays the initial map in the web view. Needs to be called and complete before adding any markers or tracks. 48 48 * Displays the initial map in the web view. Needs to be called and complete before adding any markers or tracks.
* The returned CompletableFuture will provide the final map load state, the map can be used when the load has 49 49 * The returned CompletableFuture will provide the final map load state, the map can be used when the load has
* completed with state SUCCEEDED (use CompletableFuture#whenComplete() for waiting to complete). 50 50 * completed with state SUCCEEDED (use CompletableFuture#whenComplete() for waiting to complete).
* 51 51 *
* @param mapConfig configuration of the map layers and controls 52 52 * @param mapConfig configuration of the map layers and controls
* @return the CompletableFuture which will provide the final map load state 53 53 * @return the CompletableFuture which will provide the final map load state
*/ 54 54 */
fun displayMap(mapConfig: MapConfig): CompletableFuture<Worker.State> { 55 55 fun displayMap(mapConfig: MapConfig): CompletableFuture<Worker.State> {
val finalMapLoadState = CompletableFuture<Worker.State>() 56 56 val finalMapLoadState = CompletableFuture<Worker.State>()
57 57
webEngine.loadWorker.stateProperty().addListener { _, _, newValue -> 58 58 webEngine.loadWorker.stateProperty().addListener { _, _, newValue ->
59 59
if (newValue == Worker.State.SUCCEEDED) { 60 60 if (newValue == Worker.State.SUCCEEDED) {
executeMapSetupScripts(mapConfig) 61 61 executeMapSetupScripts(mapConfig)
} 62 62 }
63 63
if (newValue == Worker.State.SUCCEEDED || newValue == Worker.State.FAILED) { 64 64 if (newValue == Worker.State.SUCCEEDED || newValue == Worker.State.FAILED) {
finalMapLoadState.complete(newValue) 65 65 finalMapLoadState.complete(newValue)
} 66 66 }
} 67 67 }
68 68
val localFileUrl: URL = LeafletMapView::class.java.getResource("/leafletmap/leafletmap.html") 69 69 val localFileUrl: URL = LeafletMapView::class.java.getResource("/leafletmap/leafletmap.html")
webEngine.load(localFileUrl.toExternalForm()) 70 70 webEngine.load(localFileUrl.toExternalForm())
return finalMapLoadState 71 71 return finalMapLoadState
} 72 72 }
73 73
private fun executeMapSetupScripts(mapConfig: MapConfig) { 74 74 private fun executeMapSetupScripts(mapConfig: MapConfig) {
75 75
// execute scripts for layer definition 76 76 // execute scripts for layer definition
mapConfig.layers.forEachIndexed { i, layer -> 77 77 mapConfig.layers.forEachIndexed { i, layer ->
execScript("var layer${i + 1} = ${layer.javaScriptCode};") 78 78 execScript("var layer${i + 1} = ${layer.javaScriptCode};")
} 79 79 }
80 80
val jsLayers = mapConfig.layers 81 81 val jsLayers = mapConfig.layers
.mapIndexed { i, layer -> "'${layer.displayName}': layer${i + 1}" } 82 82 .mapIndexed { i, layer -> "'${layer.displayName}': layer${i + 1}" }
.joinToString(", ") 83 83 .joinToString(", ")
execScript("var baseMaps = { $jsLayers };") 84 84 execScript("var baseMaps = { $jsLayers };")
85 85
// execute script for map view creation (Leaflet attribution must not be a clickable link) 86 86 // execute script for map view creation (Leaflet attribution must not be a clickable link)
execScript( 87 87 execScript(
""" 88 88 """
|var myMap = L.map('map', { 89 89 |var myMap = L.map('map', {
| center: new L.LatLng(${mapConfig.initialCenter.latitude}, ${mapConfig.initialCenter.longitude}), 90 90 | center: new L.LatLng(${mapConfig.initialCenter.latitude}, ${mapConfig.initialCenter.longitude}),
| zoom: 1, 91 91 | zoom: 1,
| zoomControl: false, 92 92 | zoomControl: false,
| layers: [layer1] 93 93 | layers: [layer1]
|}); 94 94 |});
|L.control.scale().addTo(myMap); 95 95 |L.control.scale().addTo(myMap);
96 |var markers = []
|var myRenderer = L.canvas({ padding: 0.5 }); 96 97 |var myRenderer = L.canvas({ padding: 0.5 });
|var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10}); 97 98 |var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10});
|var heatLayer = L.heatLayer([]).addTo(myMap);""".trimMargin() 98 99 |var heatLayer = L.heatLayer([]).addTo(myMap);""".trimMargin()
) 99 100 )
100 101
// eventZoomChangeIcon() 101 102 // eventZoomChangeIcon()
102 103
// execute script for layer control definition if there are multiple layers 103 104 // execute script for layer control definition if there are multiple layers
if (mapConfig.layers.size > 1) { 104 105 if (mapConfig.layers.size > 1) {
execScript( 105 106 execScript(
""" 106 107 """
|var overlayMaps = {}; 107 108 |var overlayMaps = {};
|L.control.layers(baseMaps, overlayMaps).addTo(myMap);""".trimMargin() 108 109 |L.control.layers(baseMaps, overlayMaps).addTo(myMap);""".trimMargin()
) 109 110 )
110 111
} 111 112 }
112 113
// execute script for scale control definition 113 114 // execute script for scale control definition
if (mapConfig.scaleControlConfig.show) { 114 115 if (mapConfig.scaleControlConfig.show) {
execScript( 115 116 execScript(
"L.control.scale({position: '${mapConfig.scaleControlConfig.position.positionName}', " + 116 117 "L.control.scale({position: '${mapConfig.scaleControlConfig.position.positionName}', " +
"metric: ${mapConfig.scaleControlConfig.metric}, " + 117 118 "metric: ${mapConfig.scaleControlConfig.metric}, " +
"imperial: ${!mapConfig.scaleControlConfig.metric}})" + 118 119 "imperial: ${!mapConfig.scaleControlConfig.metric}})" +
".addTo(myMap);" 119 120 ".addTo(myMap);"
) 120 121 )
} 121 122 }
122 123
// execute script for zoom control definition 123 124 // execute script for zoom control definition
if (mapConfig.zoomControlConfig.show) { 124 125 if (mapConfig.zoomControlConfig.show) {
execScript( 125 126 execScript(
"L.control.zoom({position: '${mapConfig.zoomControlConfig.position.positionName}'})" + 126 127 "L.control.zoom({position: '${mapConfig.zoomControlConfig.position.positionName}'})" +
".addTo(myMap);" 127 128 ".addTo(myMap);"
) 128 129 )
} 129 130 }
} 130 131 }
131 132
/** 132 133 /**
* Sets the view of the map to the specified geographical center position and zoom level. 133 134 * Sets the view of the map to the specified geographical center position and zoom level.
* 134 135 *
* @param position map center position 135 136 * @param position map center position
* @param zoomLevel zoom level (0 - 19 for OpenStreetMap) 136 137 * @param zoomLevel zoom level (0 - 19 for OpenStreetMap)
*/ 137 138 */
fun setView(position: LatLong, zoomLevel: Int) = 138 139 fun setView(position: LatLong, zoomLevel: Int) =
execScript("myMap.setView([${position.latitude}, ${position.longitude}], $zoomLevel);") 139 140 execScript("myMap.setView([${position.latitude}, ${position.longitude}], $zoomLevel);")
140 141
/** 141 142 /**
* Pans the map to the specified geographical center position. 142 143 * Pans the map to the specified geographical center position.
* 143 144 *
* @param position map center position 144 145 * @param position map center position
*/ 145 146 */
fun panTo(position: LatLong) = 146 147 fun panTo(position: LatLong) =
execScript("myMap.panTo([${position.latitude}, ${position.longitude}]);") 147 148 execScript("myMap.panTo([${position.latitude}, ${position.longitude}]);")
148 149
/** 149 150 /**
* Sets the zoom of the map to the specified level. 150 151 * Sets the zoom of the map to the specified level.
* 151 152 *
* @param zoomLevel zoom level (0 - 19 for OpenStreetMap) 152 153 * @param zoomLevel zoom level (0 - 19 for OpenStreetMap)
*/ 153 154 */
fun setZoom(zoomLevel: Int) = 154 155 fun setZoom(zoomLevel: Int) =
execScript("myMap.setZoom([$zoomLevel]);") 155 156 execScript("myMap.setZoom([$zoomLevel]);")
156 157
/** 157 158 /**
* Adds a Marker Object to a map 158 159 * Adds a Marker Object to a map
* 159 160 *
* @param marker the Marker Object 160 161 * @param marker the Marker Object
*/ 161 162 */
fun addMarker(marker: Marker) { 162 163 fun addMarker(marker: Marker) {
marker.addToMap(getNextMarkerName(), this) 163 164 marker.addToMap(getNextMarkerName(), this)
} 164 165 }
165 166
fun addCircle(circle: Circle) { 166 167 fun addCircle(circle: Circle) {
circle.addToMap(this) 167 168 circle.addToMap(this)
} 168 169 }
169 170
fun addZone(zone: Zone) { 170 171 fun addZone(zone: Zone) {
zone.addToMap(this) 171 172 zone.addToMap(this)
} 172 173 }
173 174
/** 174 175 /**
* Removes an existing marker from the map 175 176 * Removes an existing marker from the map
* 176 177 *
* @param marker the Marker object 177 178 * @param marker the Marker object
*/ 178 179 */
fun removeMarker(marker: Marker) { 179 180 fun removeMarker(marker: Marker) {
execScript("myMap.removeLayer(${marker.getName()});") 180 181 execScript("myMap.removeLayer(${marker.getName()});")
} 181 182 }
182 183
fun removeCircle(circle: Circle) { 183 184 fun removeCircle(circle: Circle) {
circle.removeCircle(this) 184 185 circle.removeCircle(this)
} 185 186 }
186 187
fun removeZone(zone: Zone) { 187 188 fun removeZone(zone: Zone) {
zone.removeZone() 188 189 zone.removeZone()
} 189 190 }
190 191
fun removeZone(id: String) { 191 192 fun removeZone(id: String) {
val idSanitized = id.replace("-", "") 192 193 val idSanitized = id.replace("-", "")
execScript("myMap.removeLayer(polygon$idSanitized);") 193 194 execScript("myMap.removeLayer(polygon$idSanitized);")
} 194 195 }
195 196
196 197
fun uppdateCircle(circle: Circle, latLong: LatLong, radius: Double) { 197 198 fun uppdateCircle(circle: Circle, latLong: LatLong, radius: Double) {
circle.modifyCircle(latLong, radius) 198 199 circle.modifyCircle(latLong, radius)
circle.uppdateMap() 199 200 circle.uppdateMap()
} 200 201 }
201 202
fun setEventMousePosition() { 202 203 fun setEventMousePosition() {
execScript( 203 204 execScript(
"var lat=0.0, lng=0.0;\n" + 204 205 "var lat=0.0, lng=0.0;\n" +
"myMap.addEventListener('mousemove', function(ev) {\n" + 205 206 "myMap.addEventListener('mousemove', function(ev) {\n" +
" lat = ev.latlng.lat;\n" + 206 207 " lat = ev.latlng.lat;\n" +
" lng = ev.latlng.lng;\n" + 207 208 " lng = ev.latlng.lng;\n" +
"});" 208 209 "});"
) 209 210 )
} 210 211 }
211 212
fun getMousePosition(): LatLong { 212 213 fun getMousePosition(): LatLong {
val lat = execScript("lat;") as Double 213 214 val lat = execScript("lat;") as Double
val lng = execScript("lng;") as Double 214 215 val lng = execScript("lng;") as Double
return LatLong(lat, lng) 215 216 return LatLong(lat, lng)
} 216 217 }
217 218
/** 218 219 /**
* Adds a custom marker type 219 220 * Adds a custom marker type
* 220 221 *
* @param markerName the name of the marker type 221 222 * @param markerName the name of the marker type
* @param iconUrl the url if the marker icon 222 223 * @param iconUrl the url if the marker icon
*/ 223 224 */
fun addCustomMarker(markerName: String, iconUrl: String): String { 224 225 fun addCustomMarker(markerName: String, iconUrl: String): String {
execScript( 225 226 execScript(
"var $markerName = L.icon({\n" + 226 227 "var $markerName = L.icon({\n" +
"iconUrl: '${createImage(iconUrl, "png")}',\n" + 227 228 "iconUrl: '${createImage(iconUrl, "png")}',\n" +
"iconSize: [24, 24],\n" + 228 229 "iconSize: [24, 24],\n" +
"iconAnchor: [12, 12],\n" + 229 230 "iconAnchor: [12, 12],\n" +
"});" 230 231 "});"
) 231 232 )
return markerName 232 233 return markerName
} 233 234 }
234 235
private fun createImage(path: String, type: String): String { 235 236 private fun createImage(path: String, type: String): String {
val image = ImageIO.read(File(path)) 236 237 val image = ImageIO.read(File(path))
var imageString: String? = null 237 238 var imageString: String? = null
val bos = ByteArrayOutputStream() 238 239 val bos = ByteArrayOutputStream()
239 240
try { 240 241 try {
ImageIO.write(image, type, bos) 241 242 ImageIO.write(image, type, bos)
val imageBytes = bos.toByteArray() 242 243 val imageBytes = bos.toByteArray()
243 244
val encoder = Base64.getEncoder() 244 245 val encoder = Base64.getEncoder()
imageString = encoder.encodeToString(imageBytes) 245 246 imageString = encoder.encodeToString(imageBytes)
246 247
bos.close() 247 248 bos.close()
} catch (e: IOException) { 248 249 } catch (e: IOException) {
e.printStackTrace() 249 250 e.printStackTrace()
} 250 251 }
return "data:image/$type;base64,$imageString" 251 252 return "data:image/$type;base64,$imageString"
} 252 253 }
253 254
/** 254 255 /**
* Sets the onMarkerClickListener 255 256 * Sets the onMarkerClickListener
* 256 257 *
* @param listener the onMarerClickEventListener 257 258 * @param listener the onMarerClickEventListener
*/ 258 259 */
fun onMarkerClick(listener: MarkerClickEventListener) { 259 260 fun onMarkerClick(listener: MarkerClickEventListener) {
val win = execScript("document") as JSObject 260 261 val win = execScript("document") as JSObject
win.setMember("java", this) 261 262 win.setMember("java", this)
markerClickEvent.addListener(listener) 262 263 markerClickEvent.addListener(listener)
} 263 264 }
264 265
/** 265 266 /**
* Handles the callback from the markerClickEvent 266 267 * Handles the callback from the markerClickEvent
*/ 267 268 */
fun markerClick(title: String) { 268 269 fun markerClick(title: String) {
markerClickEvent.MarkerClickEvent(title) 269 270 markerClickEvent.MarkerClickEvent(title)
} 270 271 }
271 272
/** 272 273 /**
* Sets the onMapMoveListener 273 274 * Sets the onMapMoveListener
* 274 275 *
* @param listener the MapMoveEventListener 275 276 * @param listener the MapMoveEventListener
*/ 276 277 */
fun onMapMove(listener: MapMoveEventListener) { 277 278 fun onMapMove(listener: MapMoveEventListener) {
val win = execScript("document") as JSObject 278 279 val win = execScript("document") as JSObject
win.setMember("java", this) 279 280 win.setMember("java", this)
execScript("myMap.on('moveend', function(e){ document.java.mapMove(myMap.getCenter().lat, myMap.getCenter().lng);});") 280 281 execScript("myMap.on('moveend', function(e){ document.java.mapMove(myMap.getCenter().lat, myMap.getCenter().lng);});")
mapMoveEvent.addListener(listener) 281 282 mapMoveEvent.addListener(listener)
} 282 283 }
283 284
/** 284 285 /**
* Handles the callback from the mapMoveEvent 285 286 * Handles the callback from the mapMoveEvent
*/ 286 287 */
fun mapMove(lat: Double, lng: Double) { 287 288 fun mapMove(lat: Double, lng: Double) {
val latlng = LatLong(lat, lng) 288 289 val latlng = LatLong(lat, lng)
mapMoveEvent.MapMoveEvent(latlng) 289 290 mapMoveEvent.MapMoveEvent(latlng)
} 290 291 }
291 292
/** 292 293 /**
* Sets the onMapClickListener 293 294 * Sets the onMapClickListener
* 294 295 *
* @param listener the onMapClickEventListener 295 296 * @param listener the onMapClickEventListener
*/ 296 297 */
fun onMapClick(listener: MapClickEventListener) { 297 298 fun onMapClick(listener: MapClickEventListener) {
val win = execScript("document") as JSObject 298 299 val win = execScript("document") as JSObject
win.setMember("java", this) 299 300 win.setMember("java", this)
execScript("myMap.on('click', function(e){ document.java.mapClick(e.latlng.lat, e.latlng.lng);});") 300 301 execScript("myMap.on('click', function(e){ document.java.mapClick(e.latlng.lat, e.latlng.lng);});")
mapClickEvent.addListener(listener) 301 302 mapClickEvent.addListener(listener)
} 302 303 }
303 304
/** 304 305 /**
* Handles the callback from the mapClickEvent 305 306 * Handles the callback from the mapClickEvent
*/ 306 307 */
fun mapClick(lat: Double, lng: Double) { 307 308 fun mapClick(lat: Double, lng: Double) {
val latlng = LatLong(lat, lng) 308 309 val latlng = LatLong(lat, lng)
mapClickEvent.MapClickEvent(latlng) 309 310 mapClickEvent.MapClickEvent(latlng)
} 310 311 }
311 312
/** 312 313 /**
* Draws a track path along the specified positions. 313 314 * Draws a track path along the specified positions.
* 314 315 *
* @param positions list of track positions 315 316 * @param positions list of track positions
*/ 316 317 */
fun addTrack(positions: List<LatLong>) { 317 318 fun addTrack(positions: List<LatLong>) {
318 319
val jsPositions = positions 319 320 val jsPositions = positions
.map { " [${it.latitude}, ${it.longitude}]" } 320 321 .map { " [${it.latitude}, ${it.longitude}]" }
.joinToString(", \n") 321 322 .joinToString(", \n")
322 323
execScript( 323 324 execScript(
""" 324 325 """
|var latLngs = [ 325 326 |var latLngs = [
|$jsPositions 326 327 |$jsPositions
|]; 327 328 |];
|var polyline = L.polyline(latLngs, {color: 'red', weight: 2}).addTo(myMap);""".trimMargin() 328 329 |var polyline = L.polyline(latLngs, {color: 'red', weight: 2}).addTo(myMap);""".trimMargin()
) 329 330 )
} 330 331 }
331 332
fun clearAllLayer() { 332 333 fun clearAllLayer() {
execScript(""" 333 334 execScript("""
myMap.eachLayer(function (layer) { 334 335 myMap.eachLayer(function (layer) {
map.removeLayer(layer); 335 336 map.removeLayer(layer);
}); 336 337 });
""".trimIndent()) 337 338 """.trimIndent())
} 338 339 }
339 340
fun addTrack(positions: List<LatLong>, id: String, color: Color, tooltip: String) { 340 341 fun addTrack(positions: List<LatLong>, id: String, color: Color, tooltip: String) {
341 342
val jsPositions = positions 342 343 val jsPositions = positions
.map { " [${it.latitude}, ${it.longitude}]" } 343 344 .map { " [${it.latitude}, ${it.longitude}]" }
.joinToString(", \n") 344 345 .joinToString(", \n")
345 346
val cleanTooltip = tooltip.replace("'", "&apos;") 346 347 val cleanTooltip = tooltip.replace("'", "&apos;")
execScript( 347 348 execScript(
""" 348 349 """
|var latLngs = [ 349 350 |var latLngs = [
|$jsPositions 350 351 |$jsPositions
|]; 351 352 |];
|var color = "rgb(${Math.floor(color.getRed() * 255).toInt()} ,${Math.floor(color.getGreen() * 255) 352 353 |var color = "rgb(${Math.floor(color.getRed() * 255).toInt()} ,${Math.floor(color.getGreen() * 255)
.toInt()},${Math.floor(color.getBlue() * 255).toInt()})"; 353 354 .toInt()},${Math.floor(color.getBlue() * 255).toInt()})";
|var polyline$id = L.polyline(latLngs, {color: color, weight: 2, zIndexOffset: 200}).bindTooltip('$cleanTooltip', {sticky: true}).addTo(trackGroup)""".trimMargin() 354 355 |var polyline$id = L.polyline(latLngs, {color: color, weight: 2, zIndexOffset: 200}).bindTooltip('$cleanTooltip', {sticky: true}).addTo(trackGroup)""".trimMargin()
) 355 356 )
} 356 357 }
357 358
fun makeVesselTrackTransparent(id: String) { 358 359 fun makeVesselTrackTransparent(id: String) {
execScript("polyline$id.setStyle({opacity: 0.5});") 359 360 execScript("polyline$id.setStyle({opacity: 0.5});")
} 360 361 }
361 362
fun highlightTrack(id: String) { 362 363 fun highlightTrack(id: String) {
execScript("polyline$id.setStyle({weight: 4});") 363 364 execScript("polyline$id.setStyle({weight: 4});")
} 364 365 }
365 366
fun normalizeVesselTrack(id: String) { 366 367 fun normalizeVesselTrack(id: String) {
execScript("polyline$id.setStyle({opacity: 1,weight: 2});") 367 368 execScript("polyline$id.setStyle({opacity: 1,weight: 2});")
src/main/kotlin/map/MapDisplayer.kt View file @ 78935bd
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 clearMarker(map)
} 9 10 }
10 11
fun clearMapCluster(map: LeafletMapView) { 11 12 fun clearMapCluster(map: LeafletMapView) {
map.execScript( 12 13 map.execScript(
""" 13 14 """
|myMap.removeLayer(markerClusters); 14 15 |myMap.removeLayer(markerClusters);
|var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10}); 15 16 |var markerClusters = L.markerClusterGroup({spiderfyOnMaxZoom: false, disableClusteringAtZoom: 10});
""".trimMargin() 16 17 """.trimMargin()
) 17 18 )
} 18 19 }
19 20
fun clearMapCanvas(map: LeafletMapView) { 20 21 fun clearMapCanvas(map: LeafletMapView) {
map.execScript( 21 22 map.execScript(
""" 22 23 """
|myRenderer.removeFrom(myMap); 23 24 |myRenderer.removeFrom(myMap);
|var myRenderer = L.canvas({ padding: 0.5 }); 24 25 |var myRenderer = L.canvas({ padding: 0.5 });
""".trimMargin() 25 26 """.trimMargin()
) 26 27 )
} 27 28 }
28 29
fun clearHeatMap(map: LeafletMapView) { 29 30 fun clearHeatMap(map: LeafletMapView) {
map.execScript( 30 31 map.execScript(
""" 31 32 """
|heatLayer.removeFrom(myMap); 32 33 |heatLayer.removeFrom(myMap);
|var heatLayer = L.heatLayer([]).addTo(myMap); 33 34 |var heatLayer = L.heatLayer([]).addTo(myMap);
""".trimMargin() 34 35 """.trimMargin()
) 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
fun displayAllMessageOnMap(map: LeafletMapView) { 38 50 fun displayAllMessageOnMap(map: LeafletMapView) {
clearMap(map) 39 51 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 40 52 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 41 53 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 54 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)")
} 43 55 }
} 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
fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) { 47 67 fun displayAllMessageOnMap(map: LeafletMapView, selectedMMSI: String) {
clearMap(map) 48 68 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 49 69 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 50 70 value.messages.forEach { (_, message) ->
if (selectedMMSI == message.mmsi.value) { 51 71 if (selectedMMSI == message.mmsi.value) {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap)") 52 72 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap)")
} else { 53 73 } else {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)") 54 74 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}).addTo(myMap)")
} 55 75 }
} 56 76 }
} 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
fun displayClusterMessageOnMap(map: LeafletMapView) { 60 92 fun displayClusterMessageOnMap(map: LeafletMapView) {
clearMap(map) 61 93 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 62 94 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 63 95 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 96 map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));")
} 65 97 }
} 66 98 }
map.execScript("myMap.addLayer(markerClusters);") 67 99 map.execScript("myMap.addLayer(markerClusters);")
} 68 100 }
69 101
fun displayTargetedVessels(map: LeafletMapView) { 70 102 fun displayTimedClusterMessageOnMap(map: LeafletMapView) {
clearMap(map) 71 103 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 72 104 observableVessel.vessels.forEach { (_, value) ->
val message = value.messageToDisplay ?: return@forEach 73 105 val message = value.messageToDisplay ?: return@forEach
map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") 74 106 map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {radius: 0.01, color: '#${message.getHexColorStroke()}'}));")
} 75 107 }
map.execScript("myMap.addLayer(markerClusters);") 76 108 map.execScript("myMap.addLayer(markerClusters);")
} 77 109 }
78 110
fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) { 79 111 fun displayClusterMessageOnMap(map: LeafletMapView, selectedMMSI: String) {
clearMap(map) 80 112 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 81 113 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 82 114 value.messages.forEach { (_, message) ->
if (selectedMMSI == message.mmsi.value) { 83 115 if (selectedMMSI == message.mmsi.value) {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") 84 116 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);")
} else { 85 117 } else {
map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));") 86 118 map.execScript("markerClusters.addLayer(L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 0.01, color: '#${message.getHexColorStroke()}'}));")
} 87 119 }
} 88 120 }
} 89 121 }
map.execScript("myMap.addLayer(markerClusters);") 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
fun displayHeatMapOnMap(map: LeafletMapView) { 93 138 fun displayHeatMapOnMap(map: LeafletMapView) {
clearMap(map) 94 139 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 95 140 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 96 141 value.messages.forEach { (_, message) ->
map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") 97 142 map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);")
} 98 143 }
} 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
fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) { 102 155 fun displayHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) {
clearMap(map) 103 156 clearMap(map)
observableVessel.vessels.forEach { (_, value) -> 104 157 observableVessel.vessels.forEach { (_, value) ->
value.messages.forEach { (_, message) -> 105 158 value.messages.forEach { (_, message) ->
if (selectedMMSI == message.mmsi.value) { 106 159 if (selectedMMSI == message.mmsi.value) {
map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);") 107 160 map.execScript("L.circleMarker([${message.latitude.value}, ${message.longitude.value}], {renderer: myRenderer, radius: 2, color: '#ff4040'}).addTo(myMap);")
} else { 108 161 } else {
map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);") 109 162 map.execScript("heatLayer.addLatLng([${message.latitude.value}, ${message.longitude.value}]);")
} 110 163 }
} 111 164 }
} 112 165 }
map.execScript("myMap.addLayer(markerClusters);") 113 166 map.execScript("myMap.addLayer(markerClusters);")
167 }
168
169 fun displayTimedHeatMapOnMap(map: LeafletMapView, selectedMMSI: String) {
src/main/resources/gui/timePanel.fxml View file @ 78935bd
<?xml version="1.0" encoding="UTF-8"?> 1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2
<?import javafx.geometry.*?> 3 3 <?import javafx.geometry.*?>
<?import javafx.scene.control.*?> 4 4 <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> 5 5 <?import javafx.scene.layout.*?>
6 6
<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"> 7 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">
<children> 8 8 <children>
<Button fx:id="timePlay" alignment="CENTER" mnemonicParsing="false" text="Play"> 9 9 <Button fx:id="timePlay" alignment="CENTER" mnemonicParsing="false" text="Play">
<HBox.margin> 10 10 <HBox.margin>
<Insets left="5.0" right="5.0" /> 11 11 <Insets left="5.0" right="5.0" />
</HBox.margin></Button> 12 12 </HBox.margin></Button>
<Button fx:id="timeStop" mnemonicParsing="false" text="Stop"> 13 13 <Button fx:id="timeStop" mnemonicParsing="false" text="Stop">
<HBox.margin> 14 14 <HBox.margin>
<Insets left="5.0" right="5.0" /> 15 15 <Insets left="5.0" right="5.0" />
</HBox.margin></Button> 16 16 </HBox.margin></Button>
<Slider fx:id="timeSlider"> 17 17 <Slider fx:id="timeSlider" prefHeight="14.0" prefWidth="475.0">
<HBox.margin> 18 18 <HBox.margin>
<Insets left="5.0" right="5.0" /> 19 19 <Insets left="5.0" right="5.0" />
</HBox.margin></Slider> 20 20 </HBox.margin></Slider>
</children> 21 21 </children>