Commit 43370abfea7cd24e86ea747adf23c021031c24dc
1 parent
53f01ecc34
Exists in
master
and in
1 other branch
clear map canvas when importing new data set
Showing 2 changed files with 7 additions and 3 deletions Inline Diff
src/main/kotlin/map/CircleMarkerGenerator.kt
View file @
43370ab
package map | 1 | 1 | package map | |
2 | 2 | |||
import application.model.observableMessages | 3 | 3 | import application.model.observableMessages | |
4 | 4 | |||
fun clearMap(map: LeafletMapView) { | 5 | 5 | fun clearMapCanvas(map: LeafletMapView) { | |
map.clearAllLayer() | 6 | 6 | map.execScript(""" | |
7 | |myRenderer.removeFrom(myMap) | |||
8 | |var myRenderer = L.canvas({ padding: 0.5 }); | |||
9 | """.trimMargin()) | |||
} | 7 | 10 | } | |
8 | 11 | |||
fun displayMessageOnMap(map: LeafletMapView) { | 9 | 12 | fun displayMessageOnMap(map: LeafletMapView) { | |
13 | clearMapCanvas(map) | |||
observableMessages.vessels.forEach { (_, value) -> | 10 | 14 | observableMessages.vessels.forEach { (_, value) -> | |
value.messages.forEach { (_, message) -> | 11 | 15 | value.messages.forEach { (_, message) -> | |
map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01}).addTo(myMap)") | 12 | 16 | map.execScript("L.circleMarker([${message.latitude}, ${message.longitude}], {renderer: myRenderer, radius: 0.01}).addTo(myMap)") | |
} | 13 | 17 | } | |
} | 14 | 18 | } |
src/main/kotlin/map/LeafletMapView.kt
View file @
43370ab
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: 5, | 91 | 91 | | zoom: 5, | |
| 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); | |
|var myRenderer = L.canvas({ padding: 0.5 });""".trimMargin() | 96 | 96 | |var myRenderer = L.canvas({ padding: 0.5 });""".trimMargin() | |
) | 97 | 97 | ) | |
98 | 98 | |||
// eventZoomChangeIcon() | 99 | 99 | // eventZoomChangeIcon() | |
100 | 100 | |||
// execute script for layer control definition if there are multiple layers | 101 | 101 | // execute script for layer control definition if there are multiple layers | |
if (mapConfig.layers.size > 1) { | 102 | 102 | if (mapConfig.layers.size > 1) { | |
execScript( | 103 | 103 | execScript( | |
""" | 104 | 104 | """ | |
|var overlayMaps = {}; | 105 | 105 | |var overlayMaps = {}; | |
|L.control.layers(baseMaps, overlayMaps).addTo(myMap);""".trimMargin() | 106 | 106 | |L.control.layers(baseMaps, overlayMaps).addTo(myMap);""".trimMargin() | |
) | 107 | 107 | ) | |
108 | 108 | |||
} | 109 | 109 | } | |
110 | 110 | |||
// execute script for scale control definition | 111 | 111 | // execute script for scale control definition | |
if (mapConfig.scaleControlConfig.show) { | 112 | 112 | if (mapConfig.scaleControlConfig.show) { | |
execScript( | 113 | 113 | execScript( | |
"L.control.scale({position: '${mapConfig.scaleControlConfig.position.positionName}', " + | 114 | 114 | "L.control.scale({position: '${mapConfig.scaleControlConfig.position.positionName}', " + | |
"metric: ${mapConfig.scaleControlConfig.metric}, " + | 115 | 115 | "metric: ${mapConfig.scaleControlConfig.metric}, " + | |
"imperial: ${!mapConfig.scaleControlConfig.metric}})" + | 116 | 116 | "imperial: ${!mapConfig.scaleControlConfig.metric}})" + | |
".addTo(myMap);" | 117 | 117 | ".addTo(myMap);" | |
) | 118 | 118 | ) | |
} | 119 | 119 | } | |
120 | 120 | |||
// execute script for zoom control definition | 121 | 121 | // execute script for zoom control definition | |
if (mapConfig.zoomControlConfig.show) { | 122 | 122 | if (mapConfig.zoomControlConfig.show) { | |
execScript( | 123 | 123 | execScript( | |
"L.control.zoom({position: '${mapConfig.zoomControlConfig.position.positionName}'})" + | 124 | 124 | "L.control.zoom({position: '${mapConfig.zoomControlConfig.position.positionName}'})" + | |
".addTo(myMap);" | 125 | 125 | ".addTo(myMap);" | |
) | 126 | 126 | ) | |
} | 127 | 127 | } | |
} | 128 | 128 | } | |
129 | 129 | |||
/** | 130 | 130 | /** | |
* Sets the view of the map to the specified geographical center position and zoom level. | 131 | 131 | * Sets the view of the map to the specified geographical center position and zoom level. | |
* | 132 | 132 | * | |
* @param position map center position | 133 | 133 | * @param position map center position | |
* @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | 134 | 134 | * @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | |
*/ | 135 | 135 | */ | |
fun setView(position: LatLong, zoomLevel: Int) = | 136 | 136 | fun setView(position: LatLong, zoomLevel: Int) = | |
execScript("myMap.setView([${position.latitude}, ${position.longitude}], $zoomLevel);") | 137 | 137 | execScript("myMap.setView([${position.latitude}, ${position.longitude}], $zoomLevel);") | |
138 | 138 | |||
/** | 139 | 139 | /** | |
* Pans the map to the specified geographical center position. | 140 | 140 | * Pans the map to the specified geographical center position. | |
* | 141 | 141 | * | |
* @param position map center position | 142 | 142 | * @param position map center position | |
*/ | 143 | 143 | */ | |
fun panTo(position: LatLong) = | 144 | 144 | fun panTo(position: LatLong) = | |
execScript("myMap.panTo([${position.latitude}, ${position.longitude}]);") | 145 | 145 | execScript("myMap.panTo([${position.latitude}, ${position.longitude}]);") | |
146 | 146 | |||
/** | 147 | 147 | /** | |
* Sets the zoom of the map to the specified level. | 148 | 148 | * Sets the zoom of the map to the specified level. | |
* | 149 | 149 | * | |
* @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | 150 | 150 | * @param zoomLevel zoom level (0 - 19 for OpenStreetMap) | |
*/ | 151 | 151 | */ | |
fun setZoom(zoomLevel: Int) = | 152 | 152 | fun setZoom(zoomLevel: Int) = | |
execScript("myMap.setZoom([$zoomLevel]);") | 153 | 153 | execScript("myMap.setZoom([$zoomLevel]);") | |
154 | 154 | |||
/** | 155 | 155 | /** | |
* Adds a Marker Object to a map | 156 | 156 | * Adds a Marker Object to a map | |
* | 157 | 157 | * | |
* @param marker the Marker Object | 158 | 158 | * @param marker the Marker Object | |
*/ | 159 | 159 | */ | |
fun addMarker(marker: Marker) { | 160 | 160 | fun addMarker(marker: Marker) { | |
marker.addToMap(getNextMarkerName(), this) | 161 | 161 | marker.addToMap(getNextMarkerName(), this) | |
} | 162 | 162 | } | |
163 | 163 | |||
fun addCircle(circle: Circle) { | 164 | 164 | fun addCircle(circle: Circle) { | |
circle.addToMap(this) | 165 | 165 | circle.addToMap(this) | |
} | 166 | 166 | } | |
167 | 167 | |||
fun addZone(zone: Zone) { | 168 | 168 | fun addZone(zone: Zone) { | |
zone.addToMap(this) | 169 | 169 | zone.addToMap(this) | |
} | 170 | 170 | } | |
171 | 171 | |||
/** | 172 | 172 | /** | |
* Removes an existing marker from the map | 173 | 173 | * Removes an existing marker from the map | |
* | 174 | 174 | * | |
* @param marker the Marker object | 175 | 175 | * @param marker the Marker object | |
*/ | 176 | 176 | */ | |
fun removeMarker(marker: Marker) { | 177 | 177 | fun removeMarker(marker: Marker) { | |
execScript("myMap.removeLayer(${marker.getName()});") | 178 | 178 | execScript("myMap.removeLayer(${marker.getName()});") | |
} | 179 | 179 | } | |
180 | 180 | |||
fun removeCircle(circle: Circle) { | 181 | 181 | fun removeCircle(circle: Circle) { | |
circle.removeCircle(this) | 182 | 182 | circle.removeCircle(this) | |
} | 183 | 183 | } | |
184 | 184 | |||
fun removeZone(zone: Zone) { | 185 | 185 | fun removeZone(zone: Zone) { | |
zone.removeZone() | 186 | 186 | zone.removeZone() | |
} | 187 | 187 | } | |
188 | 188 | |||
fun removeZone(id: String) { | 189 | 189 | fun removeZone(id: String) { | |
val idSanitized = id.replace("-", "") | 190 | 190 | val idSanitized = id.replace("-", "") | |
execScript("myMap.removeLayer(polygon$idSanitized);") | 191 | 191 | execScript("myMap.removeLayer(polygon$idSanitized);") | |
} | 192 | 192 | } | |
193 | 193 | |||
194 | 194 | |||
fun uppdateCircle(circle: Circle, latLong: LatLong, radius: Double) { | 195 | 195 | fun uppdateCircle(circle: Circle, latLong: LatLong, radius: Double) { | |
circle.modifyCircle(latLong, radius) | 196 | 196 | circle.modifyCircle(latLong, radius) | |
circle.uppdateMap() | 197 | 197 | circle.uppdateMap() | |
} | 198 | 198 | } | |
199 | 199 | |||
fun setEventMousePosition() { | 200 | 200 | fun setEventMousePosition() { | |
execScript( | 201 | 201 | execScript( | |
"var lat=0.0, lng=0.0;\n" + | 202 | 202 | "var lat=0.0, lng=0.0;\n" + | |
"myMap.addEventListener('mousemove', function(ev) {\n" + | 203 | 203 | "myMap.addEventListener('mousemove', function(ev) {\n" + | |
" lat = ev.latlng.lat;\n" + | 204 | 204 | " lat = ev.latlng.lat;\n" + | |
" lng = ev.latlng.lng;\n" + | 205 | 205 | " lng = ev.latlng.lng;\n" + | |
"});" | 206 | 206 | "});" | |
) | 207 | 207 | ) | |
} | 208 | 208 | } | |
209 | 209 | |||
fun getMousePosition(): LatLong { | 210 | 210 | fun getMousePosition(): LatLong { | |
val lat = execScript("lat;") as Double | 211 | 211 | val lat = execScript("lat;") as Double | |
val lng = execScript("lng;") as Double | 212 | 212 | val lng = execScript("lng;") as Double | |
return LatLong(lat, lng) | 213 | 213 | return LatLong(lat, lng) | |
} | 214 | 214 | } | |
215 | 215 | |||
/** | 216 | 216 | /** | |
* Adds a custom marker type | 217 | 217 | * Adds a custom marker type | |
* | 218 | 218 | * | |
* @param markerName the name of the marker type | 219 | 219 | * @param markerName the name of the marker type | |
* @param iconUrl the url if the marker icon | 220 | 220 | * @param iconUrl the url if the marker icon | |
*/ | 221 | 221 | */ | |
fun addCustomMarker(markerName: String, iconUrl: String): String { | 222 | 222 | fun addCustomMarker(markerName: String, iconUrl: String): String { | |
execScript( | 223 | 223 | execScript( | |
"var $markerName = L.icon({\n" + | 224 | 224 | "var $markerName = L.icon({\n" + | |
"iconUrl: '${createImage(iconUrl, "png")}',\n" + | 225 | 225 | "iconUrl: '${createImage(iconUrl, "png")}',\n" + | |
"iconSize: [24, 24],\n" + | 226 | 226 | "iconSize: [24, 24],\n" + | |
"iconAnchor: [12, 12],\n" + | 227 | 227 | "iconAnchor: [12, 12],\n" + | |
"});" | 228 | 228 | "});" | |
) | 229 | 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 | 322 | """ | |
|var latLngs = [ | 323 | 323 | |var latLngs = [ | |
|$jsPositions | 324 | 324 | |$jsPositions | |
|]; | 325 | 325 | |]; | |
|var polyline = L.polyline(latLngs, {color: 'red', weight: 2}).addTo(myMap);""".trimMargin() | 326 | 326 | |var polyline = L.polyline(latLngs, {color: 'red', weight: 2}).addTo(myMap);""".trimMargin() | |
) | 327 | 327 | ) | |
} | 328 | 328 | } | |
329 | 329 | |||
fun clearAllLayer() { | 330 | 330 | fun clearAllLayer() { | |
execScript(""" | 331 | 331 | execScript(""" | |
myMap.eachLayer(function (layer) { | 332 | 332 | myMap.eachLayer(function (layer) { | |
map.removeLayer(layer); | 333 | 333 | map.removeLayer(layer); | |
}); | 334 | 334 | }); | |
""".trimIndent()) | 335 | 335 | """.trimIndent()) | |
} | 336 | 336 | } | |
337 | 337 | |||
fun addTrack(positions: List<LatLong>, id: String, color: Color, tooltip: String) { | 338 | 338 | fun addTrack(positions: List<LatLong>, id: String, color: Color, tooltip: String) { | |
339 | 339 | |||
val jsPositions = positions | 340 | 340 | val jsPositions = positions | |
.map { " [${it.latitude}, ${it.longitude}]" } | 341 | 341 | .map { " [${it.latitude}, ${it.longitude}]" } | |
.joinToString(", \n") | 342 | 342 | .joinToString(", \n") | |
343 | 343 | |||
val cleanTooltip = tooltip.replace("'", "'") | 344 | 344 | val cleanTooltip = tooltip.replace("'", "'") | |
execScript( | 345 | 345 | execScript( | |
""" | 346 | 346 | """ | |
|var latLngs = [ | 347 | 347 | |var latLngs = [ | |
|$jsPositions | 348 | 348 | |$jsPositions | |
|]; | 349 | 349 | |]; | |
|var color = "rgb(${Math.floor(color.getRed() * 255).toInt()} ,${Math.floor(color.getGreen() * 255) | 350 | 350 | |var color = "rgb(${Math.floor(color.getRed() * 255).toInt()} ,${Math.floor(color.getGreen() * 255) | |
.toInt()},${Math.floor(color.getBlue() * 255).toInt()})"; | 351 | 351 | .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() | 352 | 352 | |var polyline$id = L.polyline(latLngs, {color: color, weight: 2, zIndexOffset: 200}).bindTooltip('$cleanTooltip', {sticky: true}).addTo(trackGroup)""".trimMargin() | |
) | 353 | 353 | ) | |
} | 354 | 354 | } | |
355 | 355 | |||
fun makeVesselTrackTransparent(id: String) { | 356 | 356 | fun makeVesselTrackTransparent(id: String) { | |
execScript("polyline$id.setStyle({opacity: 0.5});") | 357 | 357 | execScript("polyline$id.setStyle({opacity: 0.5});") | |
} | 358 | 358 | } | |
359 | 359 | |||
fun highlightTrack(id: String) { | 360 | 360 | fun highlightTrack(id: String) { | |
execScript("polyline$id.setStyle({weight: 4});") | 361 | 361 | execScript("polyline$id.setStyle({weight: 4});") | |
} | 362 | 362 | } | |
363 | 363 | |||
fun normalizeVesselTrack(id: String) { | 364 | 364 | fun normalizeVesselTrack(id: String) { | |
execScript("polyline$id.setStyle({opacity: 1,weight: 2});") | 365 | 365 | execScript("polyline$id.setStyle({opacity: 1,weight: 2});") | |
} | 366 | 366 | } |