17. April 2017
Stefan Saring
0

LeafletMap – a map component for JavaFX

JavaFX is the new de facto standard for desktop Java application for some years now. Although, it already provides lots of typical UI components, there is always demand for other controls with special requirements for the application to be build.

This was also the case in my open-source project SportsTracker, which has been migrated from Swing to JavaFX some time ago. The user of SportsTracker want to see the recorded cycling or running exercises on a map and they also want to be able to replay the track and see the details of the track positions. SportsTracker already had such a map component, but this was still Swing based. Due to missing features and integration problems when using Swing in JavaFX applications (and some not so nice workarounds), I’ve decided to replace the map viewer with a JavaFX map component.

The need for a map viewer is nothing special nowadays, so I’ve searched for existing 3rd party components. As expected, there were some and these two were looking most promising:

  • GMapsFX: This component supports Google Maps only. For displaying sporting activities, it’s better to use OpenStreetMap and its layer derivates instead. Furthermore, the developer must accept the Google Terms of Service, they are also not free for commercial applications.
  • Gluon Maps: In contrast to GMapsFX, this map component uses OpenStreetMap only and provides basic layering support. Unfortunately, it doesn’t provide the needed controls (zoom, layers, scale) and support for custom markers and tracks. Initial tests has shown that the map viewer contains several bugs, the development is also not very active.

Sadly, none of them matches the SportsTracker requirements, so I needed to create a new map viewer component.

Side trip to the JavaScript universe

When searching for map components, I’ve realized that JavaScript developers have better choices. The best looking option was the open-source Leaflet project. Although this JavaScript library provides all needed features, it is still very lightweight and can be extended by using several available plugins.

One of the best JavaFX strengths is the embedded WebKit-based web browser component called WebView. Because it also provides an interface for executing JavaScript code it’s possible to create an JavaFX wrapper component which displays the map in a web browser by using the Leaflet library.

The initial tests were working without major problems, so I’ve decided to create a reusable component and call it:

LeafletMap

The implementation was done in Kotlin instead of Java, because this new, but very mature language provides a lot of helpful features, such as:

  • Very simple and better readable generation of JavaScript code by using String Templates.
  • Rapid and compact implementation of configuration and value objects by using Properties and Data Classes.

The current feature set of the LeafletMap component is:

  • Support for OpenStreetMap, OpenCycleMap, HikeBikeMap, MtbMap and MapBox layers. More can be added easily and the layers can be switched at runtime.
  • Configurable zoom, scale and layer controls.
  • Supports metric and imperial units.
  • Display of nameable markers in multiple colors.
  • Display of tracks with automatic fitting zoom.
  • Embedded Leaflet JavaScript library, no downloads at runtime needed.
  • Small component library, just about 120 kByte for LeafletMap and 880 kByte for the Kotlin standard library. No other dependencies needed.

Although written in Kotlin, the LeafletMap component API can be used from Java and so from other JVM languages without any problems. The project contains a simple JavaFX demo application written in Kotlin, which demonstrates the usage of the map component with layers, markers and tracks.

LeafletMap demo application

LeafletMap demo application

The usage of LeafletMap is very simple, here’s the Kotlin code for adding a default map view to the container StackPane spMapView:

val mapView = LeafletMapView()
spMapView.children.add(mapView)
mapView.displayMap(MapConfig())

If you need special layers or control configuration, you can define it in the passed MapConfig object, such as:

mapView.displayMap(MapConfig(
    layers = listOf(MapLayer.OPENSTREETMAP, MapLayer.HIKE_BIKE_MAP),
    zoomControlConfig = ZoomControlConfig(true, ControlPosition.BOTTOM_LEFT),
    scaleControlConfig = ScaleControlConfig(true, ControlPosition.BOTTOM_LEFT, metric = true)))

Because Kotlin provides default and named arguments the MapConfig API looks very builder-like without any addition effort.

If you are looking for a Java usage example, take a look at the ExerciseViewer in the SportsTracker application (class TrackPanelController) for a more complex scenario.

LeafletMap inside SportsTracker

LeafletMap inside SportsTracker

The LeafletMap component is available from the SportsTracker GitHub project sub-page. The initial stable version 1.0.0 of LeafletMap has been released together with SportsTracker 7.4.0. LeafletMap has no dependencies to SportsTracker and can be used easily in other applications. Depending on demand, there will possibly be a separate GitHub project in the future.

LeafletMap is open-source and uses the Apache License, Version 2.0.

Final hint: if you are using Leaflet in your application, make sure to use Java SE 8u131 or higher, this release contains an updated WebKit version and provides a bugfix for a memory leak in the WebView component.

Stefan Saring works as a software architect and developer at the Saxonia Systems AG in Dresden, Germany. For more than 15 years he is involved in all kind of projects from the Java Standard and Enterprise environment.

Google+ 

TeilenTweet about this on TwitterShare on Facebook0Share on Google+0Share on LinkedIn0