Commit 53f01ecc3407a1e8b0a5bc7ec5947988e380f5e2
1 parent
d06a68ec66
Exists in
master
and in
1 other branch
display message on map
Showing 22 changed files with 191 additions and 100 deletions Inline Diff
- src/main/kotlin/application/controller/MapPanelController.kt
- src/main/kotlin/application/controller/MenuBarController.kt
- src/main/kotlin/application/model/ObservableVessel.kt
- src/main/kotlin/application/model/Vessel.kt
- src/main/kotlin/application/model/VesselGenerator.kt
- src/main/kotlin/map/Circle.kt
- src/main/kotlin/map/CircleMarkerGenerator.kt
- src/main/kotlin/map/ColorMarker.kt
- src/main/kotlin/map/ControlPosition.kt
- src/main/kotlin/map/LatLong.kt
- src/main/kotlin/map/LeafletMapView.kt
- src/main/kotlin/map/MapConfig.kt
- src/main/kotlin/map/MapLayer.kt
- src/main/kotlin/map/Marker.kt
- src/main/kotlin/map/ScaleControlConfig.kt
- src/main/kotlin/map/Zone.kt
- src/main/kotlin/map/ZoomControlConfig.kt
- src/main/kotlin/map/events/MapClickEvent.kt
- src/main/kotlin/map/events/MapMoveEvent.kt
- src/main/kotlin/map/events/MarkerClickEvent.kt
- src/main/resources/gui/mapPanel.fxml
- src/main/resources/gui/windows.fxml
src/main/kotlin/application/controller/MapPanelController.kt
View file @
53f01ec
File was created | 1 | package application.controller | ||
2 | ||||
3 | import application.model.MessageListener | |||
4 | import application.model.Vessel | |||
5 | import application.model.observableMessages | |||
6 | import javafx.concurrent.Worker | |||
7 | import javafx.fxml.FXML | |||
8 | import javafx.fxml.Initializable | |||
9 | import javafx.scene.layout.StackPane | |||
10 | import map.LeafletMapView | |||
11 | import map.MapConfig | |||
12 | import map.displayMessageOnMap | |||
13 | import java.net.URL | |||
14 | import java.util.* | |||
15 | import java.util.concurrent.CompletableFuture | |||
16 | ||||
17 | class MapPanelController : Initializable, MessageListener { | |||
18 | ||||
19 | @FXML | |||
20 | private lateinit var map: StackPane | |||
21 | ||||
22 | private val mapView = LeafletMapView() | |||
23 | ||||
24 | ||||
25 | override fun initialize(location: URL?, resources: ResourceBundle?) { | |||
26 | val completeFutureMap: CompletableFuture<Worker.State> = mapView.displayMap(MapConfig()) | |||
27 | observableMessages.listeners.add(this) | |||
28 | ||||
29 | /*completeFutureMap.whenComplete{ | |||
30 | workerState, _ -> | |||
31 | if (workerState == Worker.State.SUCCEEDED) { | |||
32 | } |
src/main/kotlin/application/controller/MenuBarController.kt
View file @
53f01ec
package application.controller | 1 | 1 | package application.controller | |
2 | 2 | |||
import application.App | 3 | |||
import application.model.createVesselCollection | 4 | 3 | import application.model.createVesselCollection | |
import application.model.observableMessages | 5 | 4 | import application.model.observableMessages | |
import javafx.event.EventHandler | 6 | 5 | import javafx.event.EventHandler | |
import javafx.fxml.FXML | 7 | 6 | import javafx.fxml.FXML | |
import javafx.fxml.FXMLLoader | 8 | |||
import javafx.fxml.Initializable | 9 | 7 | import javafx.fxml.Initializable | |
import javafx.scene.Parent | 10 | |||
import javafx.scene.control.MenuBar | 11 | 8 | import javafx.scene.control.MenuBar | |
import javafx.scene.control.MenuItem | 12 | 9 | import javafx.scene.control.MenuItem | |
import javafx.stage.FileChooser | 13 | 10 | import javafx.stage.FileChooser | |
import java.net.URL | 14 | 11 | import java.net.URL | |
import java.util.* | 15 | 12 | import java.util.* | |
16 | 13 | |||
class MenuBarController : Initializable { | 17 | 14 | class MenuBarController : Initializable { | |
18 | 15 | |||
@FXML | 19 | 16 | @FXML | |
var menuBar: MenuBar = MenuBar() | 20 | 17 | var menuBar: MenuBar = MenuBar() | |
21 | 18 | |||
@FXML | 22 | 19 | @FXML | |
var import: MenuItem = MenuItem() | 23 | 20 | var import: MenuItem = MenuItem() | |
24 | 21 | |||
override fun initialize(location: URL?, resources: ResourceBundle?) { | 25 | 22 | override fun initialize(location: URL?, resources: ResourceBundle?) { | |
26 | 23 | |||
import.onAction = EventHandler { | 27 | 24 | import.onAction = EventHandler { | |
val fileChooser = FileChooser() | 28 | 25 | val fileChooser = FileChooser() | |
fileChooser.title = "Choose a file to import" | 29 | 26 | fileChooser.title = "Choose a file to import" | |
val window = menuBar.scene.window | 30 | 27 | val window = menuBar.scene.window | |
val file = fileChooser.showOpenDialog(window) | 31 | 28 | val file = fileChooser.showOpenDialog(window) |
src/main/kotlin/application/model/ObservableVessel.kt
View file @
53f01ec
package application.model | 1 | 1 | package application.model | |
2 | 2 | |||
3 | import java.util.* | |||
import kotlin.properties.Delegates | 3 | 4 | import kotlin.properties.Delegates | |
4 | 5 | |||
class ObservableVessel { | 5 | 6 | class ObservableVessel { | |
val listeners: MutableList<MessageListener> = mutableListOf() | 6 | 7 | val listeners: MutableList<MessageListener> = mutableListOf() | |
7 | 8 | |||
var vessels: MutableMap<Int?, Vessel> by Delegates.observable( | 8 | 9 | var vessels: MutableMap<Int?, Vessel> by Delegates.observable( | |
initialValue = mutableMapOf(), | 9 | 10 | initialValue = mutableMapOf(), | |
onChange = { | 10 | 11 | onChange = { | |
_, _, new -> | 11 | 12 | _, _, new -> | |
run { | 12 | 13 | run { | |
listeners.forEach { | 13 | 14 | listeners.forEach { | |
it.onValueChanged(new) | 14 | 15 | it.onValueChanged(new) | |
} | 15 | 16 | } | |
} | 16 | 17 | } |
src/main/kotlin/application/model/Vessel.kt
View file @
53f01ec
package application.model | 1 | 1 | package application.model | |
2 | 2 | |||
import java.time.LocalDateTime | 3 | 3 | import java.time.LocalDateTime | |
4 | import java.util.* | |||
4 | 5 | |||
5 | 6 | |||
class Vessel() { | 6 | 7 | class Vessel { | |
val messages: MutableMap<LocalDateTime, Message> = mutableMapOf() | 7 | 8 | val messages: SortedMap<LocalDateTime, Message> = sortedMapOf() |
src/main/kotlin/application/model/VesselGenerator.kt
View file @
53f01ec
package application.model | 1 | 1 | package application.model | |
2 | 2 | |||
import java.io.File | 3 | 3 | import java.io.File | |
4 | import java.util.* | |||
5 | import kotlin.collections.ArrayList | |||
4 | 6 | |||
fun createVesselCollection(file: File) : MutableMap<Int?, Vessel> { | 5 | 7 | fun createVesselCollection(file: File) : SortedMap<Int, Vessel> { | |
val messages : ArrayList<Message> = arrayListOf() | 6 | 8 | val messages : ArrayList<Message> = arrayListOf() | |
val vessels: MutableMap<Int?, Vessel> = mutableMapOf() | 7 | 9 | val vessels: SortedMap<Int, Vessel> = sortedMapOf() | |
8 | 10 | |||
file.forEachLine { | 9 | 11 | file.forEachLine { | |
val arrayMessage = it.split(",") | 10 | 12 | val arrayMessage = it.split(",") | |
if (arrayMessage[0].toIntOrNull() !== null) { | 11 | 13 | if (arrayMessage[0].toIntOrNull() !== null) { | |
val message = Message(arrayMessage) | 12 | 14 | val message = Message(arrayMessage) | |
messages.add(message) | 13 | 15 | messages.add(message) | |
if (!vessels.containsKey(message.mmsi)){ | 14 | 16 | if (!vessels.containsKey(message.mmsi)){ | |
vessels[message.mmsi] = Vessel() | 15 | 17 | vessels[message.mmsi] = Vessel() | |
} | 16 | 18 | } | |
vessels[message.mmsi]?.messages?.set(message.time, message) | 17 | 19 | vessels[message.mmsi]?.messages?.set(message.time, message) | |
} | 18 | 20 | } | |
19 | 21 | |||
} | 20 | 22 | } |
src/main/kotlin/map/Circle.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
import javafx.scene.paint.Color | 3 | 3 | import javafx.scene.paint.Color | |
4 | 4 | |||
class Circle private constructor(private var center: LatLong, private var title: String, private var zIndexOffset: Int) { | 5 | 5 | class Circle private constructor(private var center: LatLong, private var title: String, private var zIndexOffset: Int) { | |
private var color = Color(0.0, 0.0, 0.0, 0.0) | 6 | 6 | private var color = Color(0.0, 0.0, 0.0, 0.0) | |
private lateinit var map: LeafletMapView | 7 | 7 | private lateinit var map: LeafletMapView | |
private var isAttached = false | 8 | 8 | private var isAttached = false | |
private var isDisplayed = false | 9 | 9 | private var isDisplayed = false | |
private var radius = 0.0 | 10 | 10 | private var radius = 0.0 | |
11 | 11 | |||
constructor(position: LatLong, radius: Double, title: String, color: Color, zIndexOffset: Int) : this(position, title, zIndexOffset) { | 12 | 12 | constructor(position: LatLong, radius: Double, title: String, color: Color, zIndexOffset: Int) : this(position, title, zIndexOffset) { | |
this.color = color | 13 | 13 | this.color = color | |
this.title = title.replace("-", "") | 14 | 14 | this.title = title.replace("-", "") | |
this.center = position | 15 | 15 | this.center = position | |
this.radius = nauticalMilesToMeter(radius) | 16 | 16 | this.radius = nauticalMilesToMeter(radius) | |
} | 17 | 17 | } | |
18 | 18 | |||
internal fun addToMap(map: LeafletMapView) { | 19 | 19 | internal fun addToMap(map: LeafletMapView) { | |
this.map = map | 20 | 20 | this.map = map | |
if (map.execScript("typeof circle$title == 'undefined'") as Boolean) { | 21 | 21 | if (map.execScript("typeof circle$title == 'undefined'") as Boolean) { | |
map.execScript("var circle$title;") | 22 | 22 | map.execScript("var circle$title;") | |
} | 23 | 23 | } | |
if (!this.isAttached) { | 24 | 24 | if (!this.isAttached) { | |
val hexColor = "%02x".format((color.red * 255).toInt()) + "%02x".format((color.green * 255).toInt()) + "%02x".format((color.blue * 255).toInt()) | 25 | 25 | val hexColor = "%02x".format((color.red * 255).toInt()) + "%02x".format((color.green * 255).toInt()) + "%02x".format((color.blue * 255).toInt()) | |
map.execScript("circle$title = L.circle([${center.latitude}, ${center.longitude}], $radius, {color:'#$hexColor'}).addTo(myMap);") | 26 | 26 | map.execScript("circle$title = L.circle([${center.latitude}, ${center.longitude}], $radius, {color:'#$hexColor'}).addTo(myMap);") | |
this.isAttached = true | 27 | 27 | this.isAttached = true | |
this.isDisplayed = true | 28 | 28 | this.isDisplayed = true | |
} else if (!this.isDisplayed) { | 29 | 29 | } else if (!this.isDisplayed) { | |
map.execScript("circle$title.addTo(myMap)") | 30 | 30 | map.execScript("circle$title.addTo(myMap)") | |
this.isDisplayed = true | 31 | 31 | this.isDisplayed = true | |
} | 32 | 32 | } | |
} | 33 | 33 | } | |
34 | 34 | |||
fun modifyCircle(latLong: LatLong, radius: Double) { | 35 | 35 | fun modifyCircle(latLong: LatLong, radius: Double) { | |
this.center = latLong | 36 | 36 | this.center = latLong | |
this.radius = radius | 37 | 37 | this.radius = radius | |
this.radius = nauticalMilesToMeter(radius) | 38 | 38 | this.radius = nauticalMilesToMeter(radius) | |
} | 39 | 39 | } | |
40 | 40 | |||
fun uppdateMap() { | 41 | 41 | fun uppdateMap() { | |
if (this.isAttached && !this.isDisplayed) { | 42 | 42 | if (this.isAttached && !this.isDisplayed) { | |
map.execScript("myMap.removeLayer(circle$title);" + | 43 | 43 | map.execScript("myMap.removeLayer(circle$title);" + | |
"circle$title = L.circle([${center.latitude}, ${center.longitude}], $radius).addTo(myMap);") | 44 | 44 | "circle$title = L.circle([${center.latitude}, ${center.longitude}], $radius).addTo(myMap);") | |
this.isDisplayed = true | 45 | 45 | this.isDisplayed = true | |
} | 46 | 46 | } | |
} | 47 | 47 | } | |
48 | 48 | |||
internal fun removeCircle(map: LeafletMapView) { | 49 | 49 | internal fun removeCircle(map: LeafletMapView) { | |
if (this.isAttached && this.isDisplayed) { | 50 | 50 | if (this.isAttached && this.isDisplayed) { | |
map.execScript("myMap.removeLayer(circle$title);") | 51 | 51 | map.execScript("myMap.removeLayer(circle$title);") | |
this.isDisplayed = false | 52 | 52 | this.isDisplayed = false |
src/main/kotlin/map/CircleMarkerGenerator.kt
View file @
53f01ec
File was created | 1 | package map | ||
2 | ||||
3 | import application.model.observableMessages | |||
4 | ||||
5 | fun clearMap(map: LeafletMapView) { | |||
6 | map.clearAllLayer() | |||
7 | } | |||
8 | ||||
9 | fun displayMessageOnMap(map: LeafletMapView) { | |||
10 | observableMessages.vessels.forEach { (_, value) -> | |||
11 | value.messages.forEach { (_, message) -> | |||
12 | map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01}).addTo(myMap)") |
src/main/kotlin/map/ColorMarker.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Enumeration for all marker colors of the leaflet-color-markers JavaScript library. | 4 | 4 | * Enumeration for all marker colors of the leaflet-color-markers JavaScript library. | |
* | 5 | 5 | * | |
* @author Stefan Saring | 6 | 6 | * @author Stefan Saring | |
*/ | 7 | 7 | */ | |
enum class ColorMarker(val iconName: String) { | 8 | 8 | enum class ColorMarker(val iconName: String) { | |
9 | 9 | |||
BLUE_MARKER("blueIcon"), | 10 | 10 | BLUE_MARKER("blueIcon"), | |
RED_MARKER("redIcon"), | 11 | 11 | RED_MARKER("redIcon"), | |
GREEN_MARKER("greenIcon"), | 12 | 12 | GREEN_MARKER("greenIcon"), | |
ORANGE_MARKER("orangeIcon"), | 13 | 13 | ORANGE_MARKER("orangeIcon"), | |
YELLOW_MARKER("yellowIcon"), | 14 | 14 | YELLOW_MARKER("yellowIcon"), | |
VIOLET_MARKER("violetIcon"), | 15 | 15 | VIOLET_MARKER("violetIcon"), | |
GREY_MARKER("greyIcon"), | 16 | 16 | GREY_MARKER("greyIcon"), | |
BLACK_MARKER("blackIcon") | 17 | 17 | BLACK_MARKER("blackIcon") |
src/main/kotlin/map/ControlPosition.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Enumeration for all possible map control positions. | 4 | 4 | * Enumeration for all possible map control positions. | |
* | 5 | 5 | * | |
* @author Stefan Saring | 6 | 6 | * @author Stefan Saring | |
*/ | 7 | 7 | */ | |
enum class ControlPosition(val positionName: String) { | 8 | 8 | enum class ControlPosition(val positionName: String) { | |
9 | 9 | |||
TOP_LEFT("topleft"), | 10 | 10 | TOP_LEFT("topleft"), | |
TOP_RIGHT("topright"), | 11 | 11 | TOP_RIGHT("topright"), | |
BOTTOM_LEFT("bottomleft"), | 12 | 12 | BOTTOM_LEFT("bottomleft"), | |
BOTTOM_RIGHT("bottomright") | 13 | 13 | BOTTOM_RIGHT("bottomright") |
src/main/kotlin/map/LatLong.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Immutable value class for defining a geo position. | 4 | 4 | * Immutable value class for defining a geo position. | |
* | 5 | 5 | * | |
* @author Stefan Saring | 6 | 6 | * @author Stefan Saring | |
*/ | 7 | 7 | */ | |
data class LatLong(val latitude: Double, val longitude: Double) | 8 | 8 | data class LatLong(val latitude: Double, val longitude: Double) |
src/main/kotlin/map/LeafletMapView.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
import fdit.leafletmap.events.* | 3 | |||
import fdit.leafletmap.events.MapClickEventMaker | 4 | |||
import fdit.leafletmap.events.MapMoveEventMaker | 5 | |||
import fdit.leafletmap.events.MarkerClickEventMaker | 6 | |||
import javafx.concurrent.Worker | 7 | 3 | import javafx.concurrent.Worker | |
import javafx.scene.layout.StackPane | 8 | 4 | import javafx.scene.layout.StackPane | |
import javafx.scene.paint.Color | 9 | 5 | import javafx.scene.paint.Color | |
import javafx.scene.shape.Polygon | 10 | 6 | import javafx.scene.shape.Polygon | |
import javafx.scene.web.WebEngine | 11 | 7 | import javafx.scene.web.WebEngine | |
import javafx.scene.web.WebView | 12 | 8 | import javafx.scene.web.WebView | |
import fdit.leafletmap.events.* | 13 | 9 | import map.events.* | |
import netscape.javascript.JSObject | 14 | 10 | import netscape.javascript.JSObject | |
import java.io.ByteArrayOutputStream | 15 | 11 | import java.io.ByteArrayOutputStream | |
import java.io.File | 16 | 12 | import java.io.File | |
import java.io.IOException | 17 | 13 | import java.io.IOException | |
import java.net.URL | 18 | 14 | import java.net.URL | |
import java.util.* | 19 | 15 | import java.util.* | |
import java.util.concurrent.CompletableFuture | 20 | 16 | import java.util.concurrent.CompletableFuture | |
import javax.imageio.ImageIO | 21 | 17 | import javax.imageio.ImageIO | |
22 | 18 | |||
23 | 19 | |||
/** | 24 | 20 | /** | |
* JavaFX component for displaying OpenStreetMap based maps by using the Leaflet.js JavaScript library inside a WebView | 25 | 21 | * JavaFX component for displaying OpenStreetMap based maps by using the Leaflet.js JavaScript library inside a WebView | |
* browser component.<br/> | 26 | 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 | 27 | 23 | * This component can be embedded most easily by placing it inside a StackPane, the component uses then the size of the | |
* parent automatically. | 28 | 24 | * parent automatically. | |
* | 29 | 25 | * | |
* @author Stefan Saring | 30 | 26 | * @author Stefan Saring | |
* @author Niklas Kellner | 31 | 27 | * @author Niklas Kellner | |
*/ | 32 | 28 | */ | |
class LeafletMapView : StackPane() { | 33 | 29 | class LeafletMapView : StackPane() { | |
34 | 30 | |||
private val webView = WebView() | 35 | 31 | private val webView = WebView() | |
private val webEngine: WebEngine = webView.engine | 36 | 32 | private val webEngine: WebEngine = webView.engine | |
37 | 33 | |||
private var varNameSuffix: Int = 1 | 38 | 34 | private var varNameSuffix: Int = 1 | |
private val mapClickEvent = MapClickEventMaker() | 39 | 35 | private val mapClickEvent = MapClickEventMaker() | |
private val markerClickEvent = MarkerClickEventMaker() | 40 | 36 | private val markerClickEvent = MarkerClickEventMaker() | |
private val mapMoveEvent = MapMoveEventMaker() | 41 | 37 | private val mapMoveEvent = MapMoveEventMaker() | |
internal val zoomLimitSmallMarker = 8 | 42 | 38 | internal val zoomLimitSmallMarker = 8 | |
43 | 39 | |||
/** | 44 | 40 | /** | |
* Creates the LeafletMapView component, it does not show any map yet. | 45 | 41 | * Creates the LeafletMapView component, it does not show any map yet. | |
*/ | 46 | 42 | */ | |
init { | 47 | 43 | init { | |
this.children.add(webView) | 48 | 44 | this.children.add(webView) | |
} | 49 | 45 | } | |
50 | 46 | |||
/** | 51 | 47 | /** | |
* Displays the initial map in the web view. Needs to be called and complete before adding any markers or tracks. | 52 | 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 | 53 | 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). | 54 | 50 | * completed with state SUCCEEDED (use CompletableFuture#whenComplete() for waiting to complete). | |
* | 55 | 51 | * | |
* @param mapConfig configuration of the map layers and controls | 56 | 52 | * @param mapConfig configuration of the map layers and controls | |
* @return the CompletableFuture which will provide the final map load state | 57 | 53 | * @return the CompletableFuture which will provide the final map load state | |
*/ | 58 | 54 | */ | |
fun displayMap(mapConfig: MapConfig): CompletableFuture<Worker.State> { | 59 | 55 | fun displayMap(mapConfig: MapConfig): CompletableFuture<Worker.State> { | |
val finalMapLoadState = CompletableFuture<Worker.State>() | 60 | 56 | val finalMapLoadState = CompletableFuture<Worker.State>() | |
61 | 57 | |||
webEngine.loadWorker.stateProperty().addListener { _, _, newValue -> | 62 | 58 | webEngine.loadWorker.stateProperty().addListener { _, _, newValue -> | |
63 | 59 | |||
if (newValue == Worker.State.SUCCEEDED) { | 64 | 60 | if (newValue == Worker.State.SUCCEEDED) { | |
executeMapSetupScripts(mapConfig) | 65 | 61 | executeMapSetupScripts(mapConfig) | |
} | 66 | 62 | } | |
67 | 63 | |||
if (newValue == Worker.State.SUCCEEDED || newValue == Worker.State.FAILED) { | 68 | 64 | if (newValue == Worker.State.SUCCEEDED || newValue == Worker.State.FAILED) { | |
finalMapLoadState.complete(newValue) | 69 | 65 | finalMapLoadState.complete(newValue) | |
} | 70 | 66 | } | |
} | 71 | 67 | } | |
72 | 68 | |||
val localFileUrl: URL = LeafletMapView::class.java.getResource("/leafletmap/leafletmap.html") | 73 | 69 | val localFileUrl: URL = LeafletMapView::class.java.getResource("/leafletmap/leafletmap.html") | |
webEngine.load(localFileUrl.toExternalForm()) | 74 | 70 | webEngine.load(localFileUrl.toExternalForm()) | |
return finalMapLoadState | 75 | 71 | return finalMapLoadState | |
} | 76 | 72 | } | |
77 | 73 | |||
private fun executeMapSetupScripts(mapConfig: MapConfig) { | 78 | 74 | private fun executeMapSetupScripts(mapConfig: MapConfig) { | |
79 | 75 | |||
// execute scripts for layer definition | 80 | 76 | // execute scripts for layer definition | |
mapConfig.layers.forEachIndexed { i, layer -> | 81 | 77 | mapConfig.layers.forEachIndexed { i, layer -> | |
execScript("var layer${i + 1} = ${layer.javaScriptCode};") | 82 | 78 | execScript("var layer${i + 1} = ${layer.javaScriptCode};") | |
} | 83 | 79 | } | |
84 | 80 | |||
val jsLayers = mapConfig.layers | 85 | 81 | val jsLayers = mapConfig.layers | |
.mapIndexed { i, layer -> "'${layer.displayName}': layer${i + 1}" } | 86 | 82 | .mapIndexed { i, layer -> "'${layer.displayName}': layer${i + 1}" } | |
.joinToString(", ") | 87 | 83 | .joinToString(", ") | |
execScript("var baseMaps = { $jsLayers };") | 88 | 84 | execScript("var baseMaps = { $jsLayers };") | |
89 | 85 | |||
// execute script for map view creation (Leaflet attribution must not be a clickable link) | 90 | 86 | // execute script for map view creation (Leaflet attribution must not be a clickable link) | |
execScript(""" | 91 | 87 | execScript( | |
88 | """ | |||
|var myMap = L.map('map', { | 92 | 89 | |var myMap = L.map('map', { | |
| center: new L.LatLng(${mapConfig.initialCenter.latitude}, ${mapConfig.initialCenter.longitude}), | 93 | 90 | | center: new L.LatLng(${mapConfig.initialCenter.latitude}, ${mapConfig.initialCenter.longitude}), | |
| zoom: 5, | 94 | 91 | | zoom: 5, | |
| zoomControl: false, | 95 | 92 | | zoomControl: false, | |
| layers: [layer1] | 96 | 93 | | layers: [layer1] | |
|}); | 97 | 94 | |}); | |
| | 98 | 95 | |L.control.scale().addTo(mymap); | |
|var markersGroup = L.featureGroup(); | 99 | 96 | |var myRenderer = L.canvas({ padding: 0.5 });""".trimMargin() | |
|myMap.addLayer(markersGroup); | 100 | 97 | ) | |
|var trackGroup = L.featureGroup(); | 101 | |||
|myMap.addLayer(trackGroup); | 102 | |||
| | 103 | |||
|myMap.addEventListener("contextmenu", function(e){}); | 104 | |||
|var attribution = myMap.attributionControl; | 105 | |||
|attribution.setPrefix('Leaflet');""".trimMargin()) | 106 | |||
107 | 98 | |||
eventZoomChangeIcon() | 108 | 99 | // eventZoomChangeIcon() | |
109 | 100 | |||
// execute script for layer control definition if there are multiple layers | 110 | 101 | // execute script for layer control definition if there are multiple layers | |
if (mapConfig.layers.size > 1) { | 111 | 102 | if (mapConfig.layers.size > 1) { | |
execScript(""" | 112 | 103 | execScript( | |
104 | """ | |||
|var overlayMaps = {}; | 113 | 105 | |var overlayMaps = {}; | |
|L.control.layers(baseMaps, overlayMaps).addTo(myMap);""".trimMargin()) | 114 | 106 | |L.control.layers(baseMaps, overlayMaps).addTo(myMap);""".trimMargin() | |
107 | ) | |||
115 | 108 | |||
} | 116 | 109 | } | |
117 | 110 | |||
// execute script for scale control definition | 118 | 111 | // execute script for scale control definition | |
if (mapConfig.scaleControlConfig.show) { | 119 | 112 | if (mapConfig.scaleControlConfig.show) { | |
execScript("L.control.scale({position: '${mapConfig.scaleControlConfig.position.positionName}', " + | 120 | 113 | execScript( | |
"metric: ${mapConfig.scaleControlConfig.metric}, " + | 121 | 114 | "L.control.scale({position: '${mapConfig.scaleControlConfig.position.positionName}', " + | |
"imperial: ${!mapConfig.scaleControlConfig.metric}})" + | 122 | 115 | "metric: ${mapConfig.scaleControlConfig.metric}, " + | |
".addTo(myMap);") | 123 | 116 | "imperial: ${!mapConfig.scaleControlConfig.metric}})" + | |
117 | ".addTo(myMap);" | |||
118 | ) | |||
} | 124 | 119 | } | |
125 | 120 | |||
// execute script for zoom control definition | 126 | 121 | // execute script for zoom control definition | |
if (mapConfig.zoomControlConfig.show) { | 127 | 122 | if (mapConfig.zoomControlConfig.show) { | |
execScript("L.control.zoom({position: '${mapConfig.zoomControlConfig.position.positionName}'})" + | 128 | 123 | execScript( | |
".addTo(myMap);") | 129 | 124 | "L.control.zoom({position: '${mapConfig.zoomControlConfig.position.positionName}'})" + | |
125 | ".addTo(myMap);" | |||
126 | ) | |||
} | 130 | 127 | } | |
} | 131 | 128 | } | |
132 | 129 | |||
/** | 133 | 130 | /** | |
* Sets the view of the map to the specified geographical center position and zoom level. | 134 | 131 | * Sets the view of the map to the specified geographical center position and zoom level. | |
* | 135 | 132 | * | |
* @param position map center position | 136 | 133 | * @param position map center position | |
* @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | 137 | 134 | * @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | |
*/ | 138 | 135 | */ | |
fun setView(position: LatLong, zoomLevel: Int) = | 139 | 136 | fun setView(position: LatLong, zoomLevel: Int) = | |
execScript("myMap.setView([${position.latitude}, ${position.longitude}], $zoomLevel);") | 140 | 137 | execScript("myMap.setView([${position.latitude}, ${position.longitude}], $zoomLevel);") | |
141 | 138 | |||
/** | 142 | 139 | /** | |
* Pans the map to the specified geographical center position. | 143 | 140 | * Pans the map to the specified geographical center position. | |
* | 144 | 141 | * | |
* @param position map center position | 145 | 142 | * @param position map center position | |
*/ | 146 | 143 | */ | |
fun panTo(position: LatLong) = | 147 | 144 | fun panTo(position: LatLong) = | |
execScript("myMap.panTo([${position.latitude}, ${position.longitude}]);") | 148 | 145 | execScript("myMap.panTo([${position.latitude}, ${position.longitude}]);") | |
149 | 146 | |||
/** | 150 | 147 | /** | |
* Sets the zoom of the map to the specified level. | 151 | 148 | * Sets the zoom of the map to the specified level. | |
* | 152 | 149 | * | |
* @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | 153 | 150 | * @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | |
*/ | 154 | 151 | */ | |
fun setZoom(zoomLevel: Int) = | 155 | 152 | fun setZoom(zoomLevel: Int) = | |
execScript("myMap.setZoom([$zoomLevel]);") | 156 | 153 | execScript("myMap.setZoom([$zoomLevel]);") | |
157 | 154 | |||
/** | 158 | 155 | /** | |
* Adds a Marker Object to a map | 159 | 156 | * Adds a Marker Object to a map | |
* | 160 | 157 | * | |
* @param marker the Marker Object | 161 | 158 | * @param marker the Marker Object | |
*/ | 162 | 159 | */ | |
fun addMarker(marker: Marker) { | 163 | 160 | fun addMarker(marker: Marker) { | |
marker.addToMap(getNextMarkerName(), this) | 164 | 161 | marker.addToMap(getNextMarkerName(), this) | |
} | 165 | 162 | } | |
166 | 163 | |||
fun addCircle(circle: Circle) { | 167 | 164 | fun addCircle(circle: Circle) { | |
circle.addToMap(this) | 168 | 165 | circle.addToMap(this) | |
} | 169 | 166 | } | |
170 | 167 | |||
fun addZone(zone: Zone) { | 171 | 168 | fun addZone(zone: Zone) { | |
zone.addToMap(this) | 172 | 169 | zone.addToMap(this) | |
} | 173 | 170 | } | |
174 | 171 | |||
/** | 175 | 172 | /** | |
* Removes an existing marker from the map | 176 | 173 | * Removes an existing marker from the map | |
* | 177 | 174 | * | |
* @param marker the Marker object | 178 | 175 | * @param marker the Marker object | |
*/ | 179 | 176 | */ | |
fun removeMarker(marker: Marker) { | 180 | 177 | fun removeMarker(marker: Marker) { | |
execScript("myMap.removeLayer(${marker.getName()});") | 181 | 178 | execScript("myMap.removeLayer(${marker.getName()});") | |
} | 182 | 179 | } | |
183 | 180 | |||
fun removeCircle(circle: Circle) { | 184 | 181 | fun removeCircle(circle: Circle) { | |
circle.removeCircle(this) | 185 | 182 | circle.removeCircle(this) | |
} | 186 | 183 | } | |
187 | 184 | |||
fun removeZone(zone: Zone) { | 188 | 185 | fun removeZone(zone: Zone) { | |
zone.removeZone() | 189 | 186 | zone.removeZone() | |
} | 190 | 187 | } | |
191 | 188 | |||
fun removeZone(id: String) { | 192 | 189 | fun removeZone(id: String) { | |
val idSanitized = id.replace("-", "") | 193 | 190 | val idSanitized = id.replace("-", "") | |
execScript("myMap.removeLayer(polygon$idSanitized);") | 194 | 191 | execScript("myMap.removeLayer(polygon$idSanitized);") | |
} | 195 | 192 | } | |
196 | 193 | |||
197 | 194 | |||
fun uppdateCircle(circle: Circle, latLong: LatLong, radius: Double) { | 198 | 195 | fun uppdateCircle(circle: Circle, latLong: LatLong, radius: Double) { | |
circle.modifyCircle(latLong, radius) | 199 | 196 | circle.modifyCircle(latLong, radius) | |
circle.uppdateMap() | 200 | 197 | circle.uppdateMap() | |
} | 201 | 198 | } | |
202 | 199 | |||
fun setEventMousePosition() { | 203 | 200 | fun setEventMousePosition() { | |
execScript("var lat=0.0, lng=0.0;\n" + | 204 | 201 | execScript( | |
"myMap.addEventListener('mousemove', function(ev) {\n" + | 205 | 202 | "var lat=0.0, lng=0.0;\n" + | |
" lat = ev.latlng.lat;\n" + | 206 | 203 | "myMap.addEventListener('mousemove', function(ev) {\n" + | |
" lng = ev.latlng.lng;\n" + | 207 | 204 | " lat = ev.latlng.lat;\n" + | |
"});" | 208 | 205 | " lng = ev.latlng.lng;\n" + | |
206 | "});" | |||
) | 209 | 207 | ) | |
} | 210 | 208 | } | |
211 | 209 | |||
fun getMousePosition(): LatLong { | 212 | 210 | fun getMousePosition(): LatLong { | |
val lat = execScript("lat;") as Double | 213 | 211 | val lat = execScript("lat;") as Double | |
val lng = execScript("lng;") as Double | 214 | 212 | val lng = execScript("lng;") as Double | |
return LatLong(lat, lng) | 215 | 213 | return LatLong(lat, lng) | |
} | 216 | 214 | } | |
217 | 215 | |||
/** | 218 | 216 | /** | |
* Adds a custom marker type | 219 | 217 | * Adds a custom marker type | |
* | 220 | 218 | * | |
* @param markerName the name of the marker type | 221 | 219 | * @param markerName the name of the marker type | |
* @param iconUrl the url if the marker icon | 222 | 220 | * @param iconUrl the url if the marker icon | |
*/ | 223 | 221 | */ | |
fun addCustomMarker(markerName: String, iconUrl: String): String { | 224 | 222 | fun addCustomMarker(markerName: String, iconUrl: String): String { | |
execScript("var $markerName = L.icon({\n" + | 225 | 223 | execScript( | |
"iconUrl: '${createImage(iconUrl, "png")}',\n" + | 226 | 224 | "var $markerName = L.icon({\n" + | |
"iconSize: [24, 24],\n" + | 227 | 225 | "iconUrl: '${createImage(iconUrl, "png")}',\n" + | |
"iconAnchor: [12, 12],\n" + | 228 | 226 | "iconSize: [24, 24],\n" + | |
"});") | 229 | 227 | "iconAnchor: [12, 12],\n" + | |
228 | "});" | |||
229 | ) | |||
return markerName | 230 | 230 | return markerName | |
} | 231 | 231 | } | |
232 | 232 | |||
private fun createImage(path: String, type: String): String { | 233 | 233 | private fun createImage(path: String, type: String): String { | |
val image = ImageIO.read(File(path)) | 234 | 234 | val image = ImageIO.read(File(path)) | |
var imageString: String? = null | 235 | 235 | var imageString: String? = null | |
val bos = ByteArrayOutputStream() | 236 | 236 | val bos = ByteArrayOutputStream() | |
237 | 237 | |||
try { | 238 | 238 | try { | |
ImageIO.write(image, type, bos) | 239 | 239 | ImageIO.write(image, type, bos) | |
val imageBytes = bos.toByteArray() | 240 | 240 | val imageBytes = bos.toByteArray() | |
241 | 241 | |||
val encoder = Base64.getEncoder() | 242 | 242 | val encoder = Base64.getEncoder() | |
imageString = encoder.encodeToString(imageBytes) | 243 | 243 | imageString = encoder.encodeToString(imageBytes) | |
244 | 244 | |||
bos.close() | 245 | 245 | bos.close() | |
} catch (e: IOException) { | 246 | 246 | } catch (e: IOException) { | |
e.printStackTrace() | 247 | 247 | e.printStackTrace() | |
} | 248 | 248 | } | |
return "data:image/$type;base64,$imageString" | 249 | 249 | return "data:image/$type;base64,$imageString" | |
} | 250 | 250 | } | |
251 | 251 | |||
/** | 252 | 252 | /** | |
* Sets the onMarkerClickListener | 253 | 253 | * Sets the onMarkerClickListener | |
* | 254 | 254 | * | |
* @param listener the onMarerClickEventListener | 255 | 255 | * @param listener the onMarerClickEventListener | |
*/ | 256 | 256 | */ | |
fun onMarkerClick(listener: MarkerClickEventListener) { | 257 | 257 | fun onMarkerClick(listener: MarkerClickEventListener) { | |
val win = execScript("document") as JSObject | 258 | 258 | val win = execScript("document") as JSObject | |
win.setMember("java", this) | 259 | 259 | win.setMember("java", this) | |
markerClickEvent.addListener(listener) | 260 | 260 | markerClickEvent.addListener(listener) | |
} | 261 | 261 | } | |
262 | 262 | |||
/** | 263 | 263 | /** | |
* Handles the callback from the markerClickEvent | 264 | 264 | * Handles the callback from the markerClickEvent | |
*/ | 265 | 265 | */ | |
fun markerClick(title: String) { | 266 | 266 | fun markerClick(title: String) { | |
markerClickEvent.MarkerClickEvent(title) | 267 | 267 | markerClickEvent.MarkerClickEvent(title) | |
} | 268 | 268 | } | |
269 | 269 | |||
/** | 270 | 270 | /** | |
* Sets the onMapMoveListener | 271 | 271 | * Sets the onMapMoveListener | |
* | 272 | 272 | * | |
* @param listener the MapMoveEventListener | 273 | 273 | * @param listener the MapMoveEventListener | |
*/ | 274 | 274 | */ | |
fun onMapMove(listener: MapMoveEventListener) { | 275 | 275 | fun onMapMove(listener: MapMoveEventListener) { | |
val win = execScript("document") as JSObject | 276 | 276 | val win = execScript("document") as JSObject | |
win.setMember("java", this) | 277 | 277 | win.setMember("java", this) | |
execScript("myMap.on('moveend', function(e){ document.java.mapMove(myMap.getCenter().lat, myMap.getCenter().lng);});") | 278 | 278 | execScript("myMap.on('moveend', function(e){ document.java.mapMove(myMap.getCenter().lat, myMap.getCenter().lng);});") | |
mapMoveEvent.addListener(listener) | 279 | 279 | mapMoveEvent.addListener(listener) | |
} | 280 | 280 | } | |
281 | 281 | |||
/** | 282 | 282 | /** | |
* Handles the callback from the mapMoveEvent | 283 | 283 | * Handles the callback from the mapMoveEvent | |
*/ | 284 | 284 | */ | |
fun mapMove(lat: Double, lng: Double) { | 285 | 285 | fun mapMove(lat: Double, lng: Double) { | |
val latlng = LatLong(lat, lng) | 286 | 286 | val latlng = LatLong(lat, lng) | |
mapMoveEvent.MapMoveEvent(latlng) | 287 | 287 | mapMoveEvent.MapMoveEvent(latlng) | |
} | 288 | 288 | } | |
289 | 289 | |||
/** | 290 | 290 | /** | |
* Sets the onMapClickListener | 291 | 291 | * Sets the onMapClickListener | |
* | 292 | 292 | * | |
* @param listener the onMapClickEventListener | 293 | 293 | * @param listener the onMapClickEventListener | |
*/ | 294 | 294 | */ | |
fun onMapClick(listener: MapClickEventListener) { | 295 | 295 | fun onMapClick(listener: MapClickEventListener) { | |
val win = execScript("document") as JSObject | 296 | 296 | val win = execScript("document") as JSObject | |
win.setMember("java", this) | 297 | 297 | win.setMember("java", this) | |
execScript("myMap.on('click', function(e){ document.java.mapClick(e.latlng.lat, e.latlng.lng);});") | 298 | 298 | execScript("myMap.on('click', function(e){ document.java.mapClick(e.latlng.lat, e.latlng.lng);});") | |
mapClickEvent.addListener(listener) | 299 | 299 | mapClickEvent.addListener(listener) | |
} | 300 | 300 | } | |
301 | 301 | |||
/** | 302 | 302 | /** | |
* Handles the callback from the mapClickEvent | 303 | 303 | * Handles the callback from the mapClickEvent | |
*/ | 304 | 304 | */ | |
fun mapClick(lat: Double, lng: Double) { | 305 | 305 | fun mapClick(lat: Double, lng: Double) { | |
val latlng = LatLong(lat, lng) | 306 | 306 | val latlng = LatLong(lat, lng) | |
mapClickEvent.MapClickEvent(latlng) | 307 | 307 | mapClickEvent.MapClickEvent(latlng) | |
} | 308 | 308 | } | |
309 | 309 | |||
/** | 310 | 310 | /** | |
* Draws a track path along the specified positions. | 311 | 311 | * Draws a track path along the specified positions. | |
* | 312 | 312 | * | |
* @param positions list of track positions | 313 | 313 | * @param positions list of track positions | |
*/ | 314 | 314 | */ | |
fun addTrack(positions: List<LatLong>) { | 315 | 315 | fun addTrack(positions: List<LatLong>) { | |
316 | 316 | |||
val jsPositions = positions | 317 | 317 | val jsPositions = positions | |
.map { " [${it.latitude}, ${it.longitude}]" } | 318 | 318 | .map { " [${it.latitude}, ${it.longitude}]" } | |
.joinToString(", \n") | 319 | 319 | .joinToString(", \n") | |
320 | 320 | |||
execScript(""" | 321 | 321 | execScript( | |
322 | """ | |||
|var latLngs = [ | 322 | 323 | |var latLngs = [ | |
|$jsPositions | 323 | 324 | |$jsPositions | |
|]; | 324 | 325 | |]; | |
|var polyline = L.polyline(latLngs, {color: 'red', weight: 2}).addTo(myMap);""".trimMargin()) | 325 | 326 | |var polyline = L.polyline(latLngs, {color: 'red', weight: 2}).addTo(myMap);""".trimMargin() | |
327 | ) | |||
} | 326 | 328 | } | |
327 | 329 | |||
330 | fun clearAllLayer() { | |||
331 | execScript(""" | |||
332 | myMap.eachLayer(function (layer) { | |||
333 | map.removeLayer(layer); | |||
334 | }); | |||
335 | """.trimIndent()) | |||
336 | } | |||
337 | ||||
fun addTrack(positions: List<LatLong>, id: String, color: Color, tooltip: String) { | 328 | 338 | fun addTrack(positions: List<LatLong>, id: String, color: Color, tooltip: String) { | |
329 | 339 | |||
val jsPositions = positions | 330 | 340 | val jsPositions = positions | |
.map { " [${it.latitude}, ${it.longitude}]" } | 331 | 341 | .map { " [${it.latitude}, ${it.longitude}]" } | |
.joinToString(", \n") | 332 | 342 | .joinToString(", \n") | |
333 | 343 | |||
val cleanTooltip = tooltip.replace("'", "'") | 334 | 344 | val cleanTooltip = tooltip.replace("'", "'") | |
execScript(""" | 335 | 345 | execScript( | |
346 | """ | |||
|var latLngs = [ | 336 | 347 | |var latLngs = [ | |
|$jsPositions | 337 | 348 | |$jsPositions | |
|]; | 338 | 349 | |]; | |
|var color = "rgb(${Math.floor(color.getRed() * 255).toInt()} ,${Math.floor(color.getGreen() * 255).toInt()},${Math.floor(color.getBlue() * 255).toInt()})"; | 339 | 350 | |var color = "rgb(${Math.floor(color.getRed() * 255).toInt()} ,${Math.floor(color.getGreen() * 255) | |
|var polyline$id = L.polyline(latLngs, {color: color, weight: 2, zIndexOffset: 200}).bindTooltip('$cleanTooltip', {sticky: true}).addTo(trackGroup)""".trimMargin()) | 340 | 351 | .toInt()},${Math.floor(color.getBlue() * 255).toInt()})"; | |
352 | |var polyline$id = L.polyline(latLngs, {color: color, weight: 2, zIndexOffset: 200}).bindTooltip('$cleanTooltip', {sticky: true}).addTo(trackGroup)""".trimMargin() | |||
353 | ) | |||
} | 341 | 354 | } | |
342 | 355 | |||
fun makeVesselTrackTransparent(id: String) { | 343 | 356 | fun makeVesselTrackTransparent(id: String) { | |
execScript("polyline$id.setStyle({opacity: 0.5});") | 344 | 357 | execScript("polyline$id.setStyle({opacity: 0.5});") | |
} | 345 | 358 | } | |
346 | 359 | |||
fun highlightTrack(id: String) { | 347 | 360 | fun highlightTrack(id: String) { | |
execScript("polyline$id.setStyle({weight: 4});") | 348 | 361 | execScript("polyline$id.setStyle({weight: 4});") | |
} | 349 | 362 | } | |
350 | 363 | |||
fun normalizeVesselTrack(id: String) { | 351 | 364 | fun normalizeVesselTrack(id: String) { | |
execScript("polyline$id.setStyle({opacity: 1,weight: 2});") | 352 | 365 | execScript("polyline$id.setStyle({opacity: 1,weight: 2});") | |
} | 353 | 366 | } | |
354 | 367 | |||
fun eventZoomChangeIcon() { | 355 | 368 | fun eventZoomChangeIcon() { | |
execScript(""" | 356 | 369 | execScript( | |
370 | """ | |||
|myMap.on('zoomend', function() { | 357 | 371 | |myMap.on('zoomend', function() { | |
|var currentZoom = myMap.getZoom(); | 358 | 372 | |var currentZoom = myMap.getZoom(); | |
|if (currentZoom < $zoomLimitSmallMarker) { | 359 | 373 | |if (currentZoom < $zoomLimitSmallMarker) { | |
|markersGroup.eachLayer(function(layer) { | 360 | 374 | |markersGroup.eachLayer(function(layer) { | |
return layer.setIcon(aircraftSmallIcon) | 361 | 375 | return layer.setIcon(aircraftSmallIcon) | |
|}); | 362 | 376 | |}); | |
|} else { | 363 | 377 | |} else { | |
|markersGroup.eachLayer(function(layer) { | 364 | 378 | |markersGroup.eachLayer(function(layer) { | |
return layer.setIcon(aircraftIcon) | 365 | 379 | return layer.setIcon(aircraftIcon) | |
|}); | 366 | 380 | |}); | |
|} | 367 | 381 | |} | |
|}); | 368 | 382 | |}); | |
""".trimMargin()) | 369 | 383 | """.trimMargin() | |
384 | ) | |||
} | 370 | 385 | } | |
371 | 386 | |||
fun removeTrack(id: String) { | 372 | 387 | fun removeTrack(id: String) { | |
execScript("myMap.removeLayer(polyline$id);") | 373 | 388 | execScript("myMap.removeLayer(polyline$id);") | |
} | 374 | 389 | } | |
375 | 390 | |||
fun fitBoundsMarkers() { | 376 | 391 | fun fitBoundsMarkers() { | |
execScript("setTimeout(() => {myMap.fitBounds(markersGroup.getBounds().pad(0.05));}, 500);") | 377 | 392 | execScript("setTimeout(() => {myMap.fitBounds(markersGroup.getBounds().pad(0.05));}, 500);") | |
} | 378 | 393 | } | |
379 | 394 | |||
fun addZone(polygon: Polygon, id: String, color: Color) { | 380 | 395 | fun addZone(polygon: Polygon, id: String, color: Color) { | |
val points = polygon.points | 381 | 396 | val points = polygon.points | |
val latLongs = arrayListOf<LatLong>() | 382 | 397 | val latLongs = arrayListOf<LatLong>() | |
var lat: Double | 383 | 398 | var lat: Double | |
var lon = 0.0 | 384 | 399 | var lon = 0.0 | |
385 | 400 | |||
for (i in 0 until points.size) { | 386 | 401 | for (i in 0 until points.size) { | |
if (i % 2 == 0) { | 387 | 402 | if (i % 2 == 0) { | |
lon = points[i] | 388 | 403 | lon = points[i] | |
} else { | 389 | 404 | } else { | |
lat = points[i] | 390 | 405 | lat = points[i] | |
latLongs.add(LatLong(lat, lon)) | 391 | 406 | latLongs.add(LatLong(lat, lon)) | |
} | 392 | 407 | } | |
} | 393 | 408 | } | |
394 | 409 | |||
val jsPositions = latLongs | 395 | 410 | val jsPositions = latLongs | |
.map { " [${it.latitude}, ${it.longitude}]" } | 396 | 411 | .map { " [${it.latitude}, ${it.longitude}]" } | |
.joinToString(", \n") | 397 | 412 | .joinToString(", \n") |
src/main/kotlin/map/MapConfig.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Class for defining the layers and controls in the map to be shown. | 4 | 4 | * Class for defining the layers and controls in the map to be shown. | |
* | 5 | 5 | * | |
* @property layers List of layers to be shown in the map, the default layer is OpenStreetMap. If more than one layer is | 6 | 6 | * @property layers List of layers to be shown in the map, the default layer is OpenStreetMap. If more than one layer is | |
* specified, then a layer selection control will be shown in the top right corner. | 7 | 7 | * specified, then a layer selection control will be shown in the top right corner. | |
* @property zoomControlConfig Zoom control definition, by default it's shown in the top left corner. | 8 | 8 | * @property zoomControlConfig Zoom control definition, by default it's shown in the top left corner. | |
* @property scaleControlConfig Scale control definition, by default it's not shown. | 9 | 9 | * @property scaleControlConfig Scale control definition, by default it's not shown. | |
* @property initialCenter Initial center position of the map (default is London city). | 10 | 10 | * @property initialCenter Initial center position of the map (default is London city). | |
* | 11 | 11 | * | |
* @author Stefan Saring | 12 | 12 | * @author Stefan Saring | |
*/ | 13 | 13 | */ | |
class MapConfig @JvmOverloads constructor( | 14 | 14 | class MapConfig @JvmOverloads constructor( | |
15 | 15 | |||
val layers: List<MapLayer> = listOf(MapLayer.OPENSTREETMAP), | 16 | 16 | val layers: List<MapLayer> = listOf(MapLayer.OPENSTREETMAP), | |
val zoomControlConfig: ZoomControlConfig = ZoomControlConfig(), | 17 | 17 | val zoomControlConfig: ZoomControlConfig = ZoomControlConfig(), | |
val scaleControlConfig: ScaleControlConfig = ScaleControlConfig(), | 18 | 18 | val scaleControlConfig: ScaleControlConfig = ScaleControlConfig(), | |
val initialCenter: LatLong = LatLong(0.0, 0.0) | 19 | 19 | val initialCenter: LatLong = LatLong(0.0, 0.0) |
src/main/kotlin/map/MapLayer.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Enumeration for all supported map layers. | 4 | 4 | * Enumeration for all supported map layers. | |
* | 5 | 5 | * | |
* @author Stefan Saring | 6 | 6 | * @author Stefan Saring | |
*/ | 7 | 7 | */ | |
enum class MapLayer(val displayName: String, val javaScriptCode: String) { | 8 | 8 | enum class MapLayer(val displayName: String, val javaScriptCode: String) { | |
9 | 9 | |||
/** OpenStreetMap layer. */ | 10 | 10 | /** OpenStreetMap layer. */ | |
OPENSTREETMAP("OpenStreetMap", """ | 11 | 11 | OPENSTREETMAP("OpenStreetMap", """ | |
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | 12 | 12 | L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { | |
attribution: 'Map data © OpenStreetMap and contributors', noWrap: true | 13 | 13 | attribution: 'Map data © OpenStreetMap and contributors', noWrap: true | |
})"""), | 14 | 14 | })"""), | |
15 | 15 | |||
/** OpenCycleMap layer. */ | 16 | 16 | /** OpenCycleMap layer. */ | |
OPENCYCLEMAP("OpenCycleMap", """ | 17 | 17 | OPENCYCLEMAP("OpenCycleMap", """ | |
L.tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { | 18 | 18 | L.tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', { | |
attribution: '© OpenCycleMap, Map data © OpenStreetMap contributors', noWrap: true | 19 | 19 | attribution: '© OpenCycleMap, Map data © OpenStreetMap contributors', noWrap: true | |
})"""), | 20 | 20 | })"""), | |
21 | 21 | |||
/** Hike & bike maps layer (HikeBikeMap.org). */ | 22 | 22 | /** Hike & bike maps layer (HikeBikeMap.org). */ | |
HIKE_BIKE_MAP("Hike & Bike Map", """ | 23 | 23 | HIKE_BIKE_MAP("Hike & Bike Map", """ | |
L.tileLayer('http://{s}.tiles.wmflabs.org/hikebike/{z}/{x}/{y}.png', { | 24 | 24 | L.tileLayer('http://{s}.tiles.wmflabs.org/hikebike/{z}/{x}/{y}.png', { | |
attribution: '© HikeBikeMap.org, Map data © OpenStreetMap and contributors', noWrap: true | 25 | 25 | attribution: '© HikeBikeMap.org, Map data © OpenStreetMap and contributors', noWrap: true | |
})"""), | 26 | 26 | })"""), | |
27 | 27 | |||
/** MTB map (mtbmap.cz). */ | 28 | 28 | /** MTB map (mtbmap.cz). */ | |
MTB_MAP("MTB Map", """ | 29 | 29 | MTB_MAP("MTB Map", """ | |
L.tileLayer('http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png', { | 30 | 30 | L.tileLayer('http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png', { | |
attribution: '© OpenStreetMap and USGS', noWrap: true | 31 | 31 | attribution: '© OpenStreetMap and USGS', noWrap: true | |
})"""), | 32 | 32 | })"""), | |
33 | 33 | |||
/** MapBox layer in streets mode (consider: a project specific access token is required!). */ | 34 | 34 | /** MapBox layer in streets mode (consider: a project specific access token is required!). */ | |
MAPBOX("MapBox", """ | 35 | 35 | MAPBOX("MapBox", """ |
src/main/kotlin/map/Marker.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
import fdit.gui.graphicalScenarioEditor.GraphicalScenarioEditorContext | 3 | 3 | import application.model.Vessel | |
import fdit.gui.utils.tooltip.VesselTooltipUtils.formatVesselSnapshotTooltip | 4 | |||
import fdit.metamodel.vessel.Vessel | 5 | |||
6 | 4 | |||
5 | ||||
/** | 7 | 6 | /** | |
* Creates a marker at the specified geographical position. | 8 | 7 | * Creates a marker at the specified geographical position. | |
* | 9 | 8 | * | |
* @author Niklas Kellner | 10 | 9 | * @author Niklas Kellner | |
* | 11 | 10 | * | |
* @param position marker position | 12 | 11 | * @param position marker position | |
* @param title marker title shown in tooltip (pass empty string when tooltip not needed) | 13 | 12 | * @param title marker title shown in tooltip (pass empty string when tooltip not needed) | |
* @param zIndexOffset zIndexOffset (higher number means on top) | 14 | 13 | * @param zIndexOffset zIndexOffset (higher number means on top) | |
* | 15 | 14 | * | |
*/ | 16 | 15 | */ | |
class Marker private constructor(private var position: LatLong, private var zIndexOffset: Int) { | 17 | 16 | class Marker private constructor(private var position: LatLong, private var zIndexOffset: Int) { | |
private var marker = "aircraftIcon" | 18 | 17 | private var marker = "aircraftIcon" | |
private var markerSmall = "aircraftSmallIcon" | 19 | 18 | private var markerSmall = "aircraftSmallIcon" | |
private lateinit var map: LeafletMapView | 20 | 19 | private lateinit var map: LeafletMapView | |
private var attached = false | 21 | 20 | private var attached = false | |
private var clickable = false | 22 | 21 | private var clickable = false | |
private var name = "" | 23 | 22 | private var name = "" | |
private var tooltip = "" | 24 | 23 | private var tooltip = "" | |
private var rotation = 0 | 25 | 24 | private var rotation = 0 | |
private lateinit var aircraft: Vessel | 26 | 25 | private lateinit var aircraft: Vessel | |
private lateinit var context: GraphicalScenarioEditorContext | 27 | |||
private var relativeDate: Double = 0.0 | 28 | 26 | private var relativeDate: Double = 0.0 | |
29 | 27 | |||
30 | 28 | |||
constructor(position: LatLong, aircraft: Vessel, relativeDate: Double, context: GraphicalScenarioEditorContext, aircraftIcon: String, zIndexOffset: Int) : this(position, zIndexOffset){ | 31 | 29 | constructor( | |
30 | position: LatLong, | |||
31 | aircraft: Vessel, | |||
32 | relativeDate: Double, | |||
33 | aircraftIcon: String, | |||
34 | zIndexOffset: Int | |||
35 | ) : this(position, zIndexOffset) { | |||
this.aircraft = aircraft | 32 | 36 | this.aircraft = aircraft | |
this.context = context | 33 | |||
this.relativeDate = relativeDate | 34 | 37 | this.relativeDate = relativeDate | |
this.marker = aircraftIcon | 35 | 38 | this.marker = aircraftIcon | |
} | 36 | 39 | } | |
37 | 40 | |||
/** | 38 | 41 | /** | |
* Adds the marker to a map, gets called from the mapAddMarker | 39 | 42 | * Adds the marker to a map, gets called from the mapAddMarker | |
* | 40 | 43 | * | |
* @param nextMarkerName the variable name of the marker | 41 | 44 | * @param nextMarkerName the variable name of the marker | |
* @param map the LeafetMapView | 42 | 45 | * @param map the LeafetMapView | |
*/ | 43 | 46 | */ | |
internal fun addToMap(nextMarkerName: String, map: LeafletMapView) { | 44 | 47 | internal fun addToMap(nextMarkerName: String, map: LeafletMapView) { | |
this.name = nextMarkerName | 45 | 48 | this.name = nextMarkerName | |
this.map = map | 46 | 49 | this.map = map | |
this.attached = true | 47 | 50 | this.attached = true | |
map.execScript(""" | 48 | 51 | map.execScript( | |
52 | """ | |||
|var currentZoom = myMap.getZoom(); | 49 | 53 | |var currentZoom = myMap.getZoom(); | |
|var $name; | 50 | 54 | |var $name; | |
|if (currentZoom < ${map.zoomLimitSmallMarker}) { | 51 | 55 | |if (currentZoom < ${map.zoomLimitSmallMarker}) { | |
|$name = L.marker([${position.latitude}, ${position.longitude}], {title: '', icon: $markerSmall, zIndexOffset: $zIndexOffset}).addTo(markersGroup); | 52 | 56 | |$name = L.marker([${position.latitude}, ${position.longitude}], {title: '', icon: $markerSmall, zIndexOffset: $zIndexOffset}).addTo(markersGroup); | |
|} else { | 53 | 57 | |} else { | |
|$name = L.marker([${position.latitude}, ${position.longitude}], {title: '', icon: $marker, zIndexOffset: $zIndexOffset}).addTo(markersGroup); | 54 | 58 | |$name = L.marker([${position.latitude}, ${position.longitude}], {title: '', icon: $marker, zIndexOffset: $zIndexOffset}).addTo(markersGroup); | |
|} | 55 | 59 | |} | |
""".trimMargin()) | 56 | 60 | """.trimMargin() | |
setTooltip() | 57 | 61 | ) | |
62 | // setTooltip() | |||
if (clickable) { | 58 | 63 | if (clickable) { | |
setClickable() | 59 | 64 | setClickable() | |
} | 60 | 65 | } | |
} | 61 | 66 | } | |
62 | 67 | |||
fun setTooltip() { | 63 | 68 | fun setTooltip() { | |
this.tooltip = formatVesselSnapshotTooltip(aircraft, | 64 | 69 | this.tooltip = "TODO" | |
context.getGraphicalScenario().getRecording(), | 65 | |||
relativeDate) | 66 | |||
this.tooltip = tooltip.replace("\n", "<br>") | 67 | 70 | this.tooltip = tooltip.replace("\n", "<br>") | |
this.tooltip = tooltip.replace("'", "'") | 68 | 71 | this.tooltip = tooltip.replace("'", "'") | |
map.execScript("$name.bindTooltip('<div id=\"html_c92f9552ec164f36978869550cb44ffe\" style=\"width: 100.0%; height: 100.0%;\">${this.tooltip}</div>');") | 69 | 72 | map.execScript("$name.bindTooltip('<div id=\"html_c92f9552ec164f36978869550cb44ffe\" style=\"width: 100.0%; height: 100.0%;\">${this.tooltip}</div>');") | |
} | 70 | 73 | } | |
71 | 74 | |||
72 | 75 | |||
/** | 73 | 76 | /** | |
* Changes the icon of the marker | 74 | 77 | * Changes the icon of the marker | |
* | 75 | 78 | * | |
* @param newIcon the name of the new icon | 76 | 79 | * @param newIcon the name of the new icon | |
*/ | 77 | 80 | */ | |
fun changeIcon(newIcon: String) { | 78 | 81 | fun changeIcon(newIcon: String) { | |
this.marker = newIcon | 79 | 82 | this.marker = newIcon | |
if (attached) { | 80 | 83 | if (attached) { | |
map.execScript("$name.setIcon($marker);") | 81 | 84 | map.execScript("$name.setIcon($marker);") | |
} | 82 | 85 | } | |
} | 83 | 86 | } | |
84 | 87 | |||
/** | 85 | 88 | /** | |
* Changes the icon of the marker | 86 | 89 | * Changes the icon of the marker | |
* | 87 | 90 | * | |
* @param newIcon the new ColorMarker | 88 | 91 | * @param newIcon the new ColorMarker | |
*/ | 89 | 92 | */ | |
fun changeIcon(newIcon: ColorMarker) { | 90 | 93 | fun changeIcon(newIcon: ColorMarker) { | |
this.marker = newIcon.iconName | 91 | 94 | this.marker = newIcon.iconName | |
if (attached) { | 92 | 95 | if (attached) { | |
map.execScript("$name.setIcon(${newIcon.iconName});") | 93 | 96 | map.execScript("$name.setIcon(${newIcon.iconName});") | |
} | 94 | 97 | } | |
} | 95 | 98 | } | |
96 | 99 | |||
/** | 97 | 100 | /** | |
* Moves the existing marker specified by the variable name to the new geographical position. | 98 | 101 | * Moves the existing marker specified by the variable name to the new geographical position. | |
* | 99 | 102 | * | |
* @param position new marker position | 100 | 103 | * @param position new marker position | |
*/ | 101 | 104 | */ | |
fun move(position: LatLong) { | 102 | 105 | fun move(position: LatLong) { | |
this.position = position | 103 | 106 | this.position = position | |
if (attached) { | 104 | 107 | if (attached) { | |
map.execScript("$name.setLatLng([${this.position.latitude}, ${this.position.longitude}]);") | 105 | 108 | map.execScript("$name.setLatLng([${this.position.latitude}, ${this.position.longitude}]);") | |
setTooltip() | 106 | 109 | setTooltip() | |
} | 107 | 110 | } | |
} | 108 | 111 | } | |
109 | 112 | |||
fun move(position: LatLong, aircraft: Vessel, relativeDate: Double) { | 110 | 113 | fun move(position: LatLong, aircraft: Vessel, relativeDate: Double) { | |
this.aircraft = aircraft | 111 | 114 | this.aircraft = aircraft | |
this.relativeDate = relativeDate | 112 | 115 | this.relativeDate = relativeDate | |
this.position = position | 113 | 116 | this.position = position | |
if (attached) { | 114 | 117 | if (attached) { | |
map.execScript("$name.setLatLng([${this.position.latitude}, ${this.position.longitude}]);") | 115 | 118 | map.execScript("$name.setLatLng([${this.position.latitude}, ${this.position.longitude}]);") | |
} | 116 | 119 | } | |
} | 117 | 120 | } | |
118 | 121 | |||
fun setRotation(rotation: Int) { | 119 | 122 | fun setRotation(rotation: Int) { | |
if (rotation > 360 || rotation < 0) { | 120 | 123 | if (rotation > 360 || rotation < 0) { | |
this.rotation = 0 | 121 | 124 | this.rotation = 0 | |
} else { | 122 | 125 | } else { | |
this.rotation = rotation | 123 | 126 | this.rotation = rotation | |
} | 124 | 127 | } | |
if (attached) { | 125 | 128 | if (attached) { | |
map.execScript("$name.setRotationAngle(${this.rotation})") | 126 | 129 | map.execScript("$name.setRotationAngle(${this.rotation})") | |
} | 127 | 130 | } | |
} | 128 | 131 | } | |
129 | 132 | |||
130 | 133 | |||
/** | 131 | 134 | /** | |
* Sets the marker clickable | 132 | 135 | * Sets the marker clickable | |
*/ | 133 | 136 | */ | |
private fun setClickable() { | 134 | 137 | private fun setClickable() { |
src/main/kotlin/map/ScaleControlConfig.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Class for defining the scale control of the map. The scale can show either metric or imperial units. | 4 | 4 | * Class for defining the scale control of the map. The scale can show either metric or imperial units. | |
5 | 5 | |||
* @author Stefan Saring | 6 | 6 | * @author Stefan Saring | |
*/ | 7 | 7 | */ | |
class ScaleControlConfig @JvmOverloads constructor( | 8 | 8 | class ScaleControlConfig @JvmOverloads constructor( | |
val show: Boolean = false, | 9 | 9 | val show: Boolean = false, | |
val position: ControlPosition = ControlPosition.BOTTOM_LEFT, | 10 | 10 | val position: ControlPosition = ControlPosition.BOTTOM_LEFT, | |
val metric: Boolean = true) | 11 | 11 | val metric: Boolean = true | |
12 | ) | |||
src/main/kotlin/map/Zone.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | ||||
3 | import map.LatLong | |||
4 | import map.LeafletMapView | |||
2 | 5 | |||
class Zone constructor(private var title: String) { | 3 | 6 | class Zone constructor(private var title: String) { | |
private lateinit var map: LeafletMapView | 4 | 7 | private lateinit var map: LeafletMapView | |
private var isAttached = false | 5 | 8 | private var isAttached = false | |
private var isDisplayed = false | 6 | 9 | private var isDisplayed = false | |
private var positions = listOf<LatLong>() | 7 | 10 | private var positions = listOf<LatLong>() | |
8 | 11 | |||
9 | 12 | |||
fun addToMap(map: LeafletMapView) { | 10 | 13 | fun addToMap(map: LeafletMapView) { | |
this.map = map | 11 | 14 | this.map = map | |
12 | 15 | |||
if (map.execScript("typeof zone$title == 'undefined';") as Boolean) { | 13 | 16 | if (map.execScript("typeof zone$title == 'undefined';") as Boolean) { | |
map.execScript("var zone$title") | 14 | 17 | map.execScript("var zone$title") | |
} | 15 | 18 | } | |
if (!this.isAttached) { | 16 | 19 | if (!this.isAttached) { | |
17 | 20 | |||
map.execScript("var points$title = [];" + | 18 | 21 | map.execScript("var points$title = [];" + | |
"zone$title = L.polygon(points$title).addTo(myMap);") | 19 | 22 | "zone$title = L.polygon(points$title).addTo(myMap);") | |
this.isAttached = true | 20 | 23 | this.isAttached = true | |
this.isDisplayed = true | 21 | 24 | this.isDisplayed = true | |
} else if (!this.isDisplayed) { | 22 | 25 | } else if (!this.isDisplayed) { | |
map.execScript("zone$title.addTo(myMap);") | 23 | 26 | map.execScript("zone$title.addTo(myMap);") | |
this.isDisplayed = true | 24 | 27 | this.isDisplayed = true | |
} | 25 | 28 | } | |
} | 26 | 29 | } | |
27 | 30 | |||
private fun addPoint(latLong: LatLong) { | 28 | 31 | private fun addPoint(latLong: LatLong) { | |
map.execScript("points$title.push([${latLong.latitude}, ${latLong.longitude}]);") | 29 | 32 | map.execScript("points$title.push([${latLong.latitude}, ${latLong.longitude}]);") | |
} | 30 | 33 | } | |
31 | 34 | |||
fun updatePoints(positions: List<LatLong>) { | 32 | 35 | fun updatePoints(positions: List<LatLong>) { | |
this.positions = positions | 33 | 36 | this.positions = positions | |
if (map.execScript("typeof points$title == 'undefined'") as Boolean) { | 34 | 37 | if (map.execScript("typeof points$title == 'undefined'") as Boolean) { | |
map.execScript("var points$title = [];") | 35 | 38 | map.execScript("var points$title = [];") | |
} else { | 36 | 39 | } else { | |
map.execScript("points$title = [];") | 37 | 40 | map.execScript("points$title = [];") | |
} | 38 | 41 | } | |
for (position in positions) { | 39 | 42 | for (position in positions) { | |
addPoint(position) | 40 | 43 | addPoint(position) | |
} | 41 | 44 | } | |
} | 42 | 45 | } | |
43 | 46 | |||
fun updateMap() { | 44 | 47 | fun updateMap() { | |
if (this.isAttached) { | 45 | 48 | if (this.isAttached) { | |
map.execScript("myMap.removeLayer(zone$title);" + | 46 | 49 | map.execScript("myMap.removeLayer(zone$title);" + | |
"zone$title = L.polygon(points$title).addTo(myMap);") | 47 | 50 | "zone$title = L.polygon(points$title).addTo(myMap);") | |
this.isDisplayed = true | 48 | 51 | this.isDisplayed = true | |
} | 49 | 52 | } | |
} | 50 | 53 | } |
src/main/kotlin/map/ZoomControlConfig.kt
View file @
53f01ec
package fdit.leafletmap | 1 | 1 | package map | |
2 | 2 | |||
/** | 3 | 3 | /** | |
* Class for defining the zoom control of the map. | 4 | 4 | * Class for defining the zoom control of the map. | |
5 | 5 | |||
* @author Stefan Saring | 6 | 6 | * @author Stefan Saring | |
*/ | 7 | 7 | */ | |
class ZoomControlConfig @JvmOverloads constructor( | 8 | 8 | class ZoomControlConfig @JvmOverloads constructor( | |
val show: Boolean = true, | 9 | 9 | val show: Boolean = true, | |
val position: ControlPosition = ControlPosition.TOP_LEFT) | 10 | 10 | val position: ControlPosition = ControlPosition.TOP_LEFT | |
11 | ) | |||
src/main/kotlin/map/events/MapClickEvent.kt
View file @
53f01ec
package fdit.leafletmap.events | 1 | 1 | package map.events | |
2 | 2 | |||
import fdit.leafletmap.LatLong | 3 | 3 | import map.LatLong | |
import java.util.* | 4 | 4 | import java.util.* | |
5 | 5 | |||
/** | 6 | 6 | /** | |
* Handles the MapClickEvent | 7 | 7 | * Handles the MapClickEvent | |
* @author Niklas Kellner | 8 | 8 | * @author Niklas Kellner | |
*/ | 9 | 9 | */ | |
interface MapClickEventListener { | 10 | 10 | interface MapClickEventListener { | |
fun onMapClick(latLong: LatLong) | 11 | 11 | fun onMapClick(latLong: LatLong) | |
} | 12 | 12 | } | |
13 | 13 | |||
internal class MapClickEventMaker { | 14 | 14 | internal class MapClickEventMaker { | |
private val listeners = ArrayList<MapClickEventListener>() | 15 | 15 | private val listeners = ArrayList<MapClickEventListener>() | |
16 | 16 | |||
fun addListener(toAdd: MapClickEventListener) { | 17 | 17 | fun addListener(toAdd: MapClickEventListener) { | |
listeners.add(toAdd) | 18 | 18 | listeners.add(toAdd) | |
} | 19 | 19 | } | |
20 | 20 | |||
fun MapClickEvent(latLong: LatLong) { | 21 | 21 | fun MapClickEvent(latLong: LatLong) { | |
// Notify everybody that may be interested. | 22 | 22 | // Notify everybody that may be interested. | |
for (hl in listeners) | 23 | 23 | for (hl in listeners) |
src/main/kotlin/map/events/MapMoveEvent.kt
View file @
53f01ec
package fdit.leafletmap.events | 1 | 1 | package map.events | |
2 | 2 | |||
import fdit.leafletmap.LatLong | 3 | 3 | import map.LatLong | |
import java.util.* | 4 | 4 | import java.util.* | |
5 | 5 | |||
/** | 6 | 6 | /** | |
* Handles the MapMoveEvent | 7 | 7 | * Handles the MapMoveEvent | |
* | 8 | 8 | * | |
* @author Niklas Kellner | 9 | 9 | * @author Niklas Kellner | |
*/ | 10 | 10 | */ | |
interface MapMoveEventListener { | 11 | 11 | interface MapMoveEventListener { | |
fun onMapMove(center: LatLong) | 12 | 12 | fun onMapMove(center: LatLong) | |
} | 13 | 13 | } | |
14 | 14 | |||
internal class MapMoveEventMaker { | 15 | 15 | internal class MapMoveEventMaker { | |
private val listeners = ArrayList<MapMoveEventListener>() | 16 | 16 | private val listeners = ArrayList<MapMoveEventListener>() | |
17 | 17 | |||
fun addListener(toAdd: MapMoveEventListener) { | 18 | 18 | fun addListener(toAdd: MapMoveEventListener) { | |
listeners.add(toAdd) | 19 | 19 | listeners.add(toAdd) | |
} | 20 | 20 | } | |
21 | 21 | |||
fun MapMoveEvent(latLong: LatLong) { | 22 | 22 | fun MapMoveEvent(latLong: LatLong) { | |
// Notify everybody that may be interested. | 23 | 23 | // Notify everybody that may be interested. | |
for (hl in listeners) | 24 | 24 | for (hl in listeners) |
src/main/kotlin/map/events/MarkerClickEvent.kt
View file @
53f01ec
package fdit.leafletmap.events | 1 | 1 | package map.events | |
2 | 2 | |||
import java.util.* | 3 | 3 | import java.util.* | |
4 | 4 | |||
/** | 5 | 5 | /** | |
* Handles the MarkerClickEvent | 6 | 6 | * Handles the MarkerClickEvent | |
* | 7 | 7 | * | |
* @author Niklas Kellner | 8 | 8 | * @author Niklas Kellner | |
*/ | 9 | 9 | */ | |
interface MarkerClickEventListener { | 10 | 10 | interface MarkerClickEventListener { | |
fun onMarkerClick(title: String) | 11 | 11 | fun onMarkerClick(title: String) | |
} | 12 | 12 | } | |
13 | 13 | |||
internal class MarkerClickEventMaker { | 14 | 14 | internal class MarkerClickEventMaker { | |
private val listeners = ArrayList<MarkerClickEventListener>() | 15 | 15 | private val listeners = ArrayList<MarkerClickEventListener>() | |
private var listenerSet = false | 16 | 16 | private var listenerSet = false | |
17 | 17 | |||
fun addListener(toAdd: MarkerClickEventListener) { | 18 | 18 | fun addListener(toAdd: MarkerClickEventListener) { | |
listeners.add(toAdd) | 19 | 19 | listeners.add(toAdd) | |
listenerSet = true | 20 | 20 | listenerSet = true | |
} | 21 | 21 | } | |
22 | 22 | |||
fun MarkerClickEvent(title: String){ | 23 | 23 | fun MarkerClickEvent(title: String){ | |
// Notify everybody that may be interested. | 24 | 24 | // Notify everybody that may be interested. | |
for (hl in listeners) | 25 | 25 | for (hl in listeners) | |
hl.onMarkerClick(title) | 26 | 26 | hl.onMarkerClick(title) | |
} | 27 | 27 | } |
src/main/resources/gui/mapPanel.fxml
View file @
53f01ec
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | ||||
3 | <?import javafx.scene.layout.StackPane?> | |||
4 | ||||
5 | <StackPane prefHeight="150.0" prefWidth="200.0" xmlns="http://javafx.com/javafx" | |||
6 | xmlns:fx="http://javafx.com/fxml" |
src/main/resources/gui/windows.fxml
View file @
53f01ec
<?xml version="1.0" encoding="UTF-8"?> | 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | 2 | |||
3 | ||||
<?import javafx.scene.control.SplitPane?> | 4 | 3 | <?import javafx.scene.control.SplitPane?> | |
<?import javafx.scene.layout.*?> | 5 | 4 | <?import javafx.scene.layout.*?> | |
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="900.0" | 6 | 5 | <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="900.0" | |
prefWidth="1200.0" xmlns="http://javafx.com/javafx/8.0.241" xmlns:fx="http://javafx.com/fxml/1"> | 7 | 6 | prefWidth="1200.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1"> | |
<children> | 8 | 7 | <children> | |
<fx:include source="menuBar.fxml" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" | 9 | 8 | <fx:include source="menuBar.fxml" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" | |
AnchorPane.topAnchor="0.0"/> | 10 | 9 | AnchorPane.topAnchor="0.0"/> | |
<SplitPane dividerPositions="0.29797979797979796" layoutY="25.0" prefHeight="379.0" prefWidth="594.0" | 11 | 10 | <SplitPane dividerPositions="0.29797979797979796" layoutY="25.0" prefHeight="379.0" prefWidth="594.0" | |
AnchorPane.bottomAnchor="-4.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="6.0" | 12 | 11 | AnchorPane.bottomAnchor="-4.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="6.0" | |
AnchorPane.topAnchor="25.0"> | 13 | 12 | AnchorPane.topAnchor="25.0"> | |
<items> | 14 | 13 | <items> | |
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> | 15 | 14 | <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> | |
<children> | 16 | 15 | <children> | |
<fx:include source="controlPanel.fxml" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" | 17 | 16 | <fx:include source="controlPanel.fxml" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" | |
AnchorPane.topAnchor="0.0"/> | 18 | 17 | AnchorPane.topAnchor="0.0"/> | |
</children> | 19 | 18 | </children> | |
</AnchorPane> | 20 | 19 | </AnchorPane> | |
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> | 21 | 20 | <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> | |
<children> | 22 | 21 | <children> | |
<SplitPane dividerPositions="0.5" layoutX="127.0" layoutY="74.0" orientation="VERTICAL" | 23 | 22 | <SplitPane dividerPositions="0.536" layoutX="127.0" layoutY="74.0" orientation="VERTICAL" | |
prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" | 24 | 23 | prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" | |
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | 25 | 24 | AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | |
<items> | 26 | 25 | <items> | |
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0"/> | 27 | 26 | <fx:include source="mapPanel.fxml" /> | |
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0"/> | 28 | 27 | <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0"/> | |
</items> | 29 | 28 | </items> | |
</SplitPane> | 30 | 29 | </SplitPane> | |
</children> | 31 | 30 | </children> | |
</AnchorPane> | 32 | 31 | </AnchorPane> | |
</items> | 33 | 32 | </items> | |
</SplitPane> | 34 | 33 | </SplitPane> | |
</children> | 35 | 34 | </children> | |
</AnchorPane> | 36 | 35 | </AnchorPane> | |
37 | 36 |