Documentation

You are viewing documentation for Vaadin 23. View latest documentation

Map

Note
Commercial feature

A commercial Vaadin subscription is required to use Map in your project.

Map is a component for displaying geographical maps from various sources. It supports multiple layers, tiled and full-image sources, adding markers, and interaction through events.

Open in a
new tab
// Create a new map, this will use the OpenStreetMap service by default
Map map = new Map();
add(map);
Important
Breaking Changes Since 23.1

This documentation has already been updated to Vaadin 23.2. See the breaking changes to the default coordinate system and how they relate to this documentation.

Important
Map Data Subscription Not Included

The Map component uses OpenStreetMap as its default map data provider for testing and development purposes. The tile usage policy for OpenStreetMap only allows for light usage. This means it should not be used for production. A commercial map data service, or a self-hosted solution, should be arranged for production use. See the Map Sources section for a list of supported map data formats.

Viewport

Map provides interactions, controls, and APIs to control the viewport. This includes setting the center, the zoom level, and the rotation.

By default, map coordinates such as the view’s center are specified in EPSG:4326 projection — also known as latitude and longitude — unless a custom user projection is configured. See Coordinate Systems for more information.

The zoom level is a decimal number that starts at 0 as the most zoomed-out level, and then progressively increases to zoom further in. By default, the maximum zoom level is currently restricted to 28. In practical terms, the level of detail of the map data that a map service provides will determine the usefulness of higher zoom levels.

Open in a
new tab
MenuBar menuBar = new MenuBar();
SubMenu moveToSubMenu = menuBar.addItem("Move To...").getSubMenu();

// Add menu items for moving the viewport to different cities
moveToSubMenu.addItem("Berlin", e -> {
    // For Vaadin 23.1, use Coordinate.fromLonLat to create coordinates
    // from longitude and latitude
    Coordinate coordinate = new Coordinate(13.404954, 52.520008);
    map.setCenter(coordinate);
    map.setZoom(10);
});

...

// Add menu items for zooming
menuBar.addItem(zoomInIcon, e -> {
    float zoom = map.getView().getZoom();
    map.setZoom(zoom + 1);
});
menuBar.addItem(zoomOutIcon, e -> {
    float zoom = map.getView().getZoom();
    map.setZoom(zoom - 1);
});

Map Sources

Web maps can be roughly categorized as being based on tiled images, full images or vector data. Each category comes with its own set of standards and formats that define how the map data is structured and how it should be used. Map services are applications — typically servers or cloud services — that provide map data in one or more of these formats.

The Map component provides various sources for loading map data in a specific format from a map service. Each source requires the use of a specific type of layer that can render data from that source.

The following table lists the sources that can be used with Map. An example usage of each source can be found in the demo that follows:

Source Requires Description

OSM

Tile layer

Loads image tiles from the OpenStreetMap service. This source is configured as the default. It doesn’t require further configuration, as it contains presets for URL and attributions. This source should be used only for development purposes. For applications in production, you should use a commercial map service or a self-hosted solution. Read and respect the OpenStreetMap tile usage policy.

XYZ

Tile layer

Loads image tiles from a map service that supports the Slippy Map tile numbering scheme, also known as XYZ format. This source requires you to configure a URL pattern that contains placeholders for the x and y tile coordinates, as well as the z placeholder for the zoom level. For an example, see https://my-map-service.com/my-tileset/{z}/{x}/{y}.png. For the specific URL, consult the documentation of the map service that you intend to use.

Tile WMS

Tile layer

Loads image tiles from a Web Map Service (WMS). This source requires you to configure the URL to the WMS, as well as the request parameters. At a minimum, the LAYERS request parameter must be configured. For other required parameters and available values, consult the documentation of the service itself.

Open in a
new tab
private void setupOsmSource() {
    // OSM does not require any further configuration,
    // it contains presets for URL and attributions
    OSMSource source = new OSMSource();
    TileLayer tileLayer = new TileLayer();
    tileLayer.setSource(source);
    map.setBackgroundLayer(tileLayer);
}

private void setupXyzSource() {
    XYZSource.Options sourceOptions = new XYZSource.Options();
    // set the URL pattern for the map service containing x, y, and z
    // parameters
    // mapbox requires an access token, register on
    // mapbox.com to get one, and place it in the line below
    sourceOptions.setUrl(
            "https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg90?access_token=<your-access-token>");
    // using a map service usually requires setting
    // attributions with copyright notices
    sourceOptions.setAttributions(List.of(
            "<a href=\"https://www.mapbox.com/about/maps/\">© Mapbox</a>",
            "<a href=\"https://www.openstreetmap.org/about/\">© OpenStreetMap</a>"));
    sourceOptions.setAttributionsCollapsible(false);
    XYZSource source = new XYZSource(sourceOptions);
    TileLayer tileLayer = new TileLayer();
    tileLayer.setSource(source);
    map.setBackgroundLayer(tileLayer);
}

private void setupWmsSource() {
    TileWMSSource.Options sourceOptions = new TileWMSSource.Options();
    // set the URL for the WMS
    sourceOptions.setUrl("https://ows.mundialis.de/services/service");
    // WMS require configuration of request parameters,
    // at least the LAYERS parameter must be specified.
    // Required parameters and possible values can be
    // found in the respective documentation of the service
    HashMap<String, Object> params = new HashMap<>();
    params.put("LAYERS", "TOPO-WMS");
    sourceOptions.setParams(params);
    // using a map service usually requires setting
    // attributions with copyright notices
    sourceOptions.setAttributions(List.of(
            "Contains modified SRTM data (2014)/NASA, processed by <a href=\"https://www.mundialis.de\">mundialis<a/>"));
    sourceOptions.setAttributionsCollapsible(false);
    TileWMSSource source = new TileWMSSource(sourceOptions);
    TileLayer layer = new TileLayer();
    layer.setSource(source);
    map.setBackgroundLayer(layer);
}

Layers

The map component is preconfigured with a background layer showing a map from the OpenStreetMap service by default, as well as a feature layer for quickly adding geographical features, such as markers. The default background layer can be replaced, and additional layers added on top of it, such as to display overlays.

By default, layers are rendered in the order that they were added to the map, with the first-added layer rendered first, and the last-added layer rendered last. For finer-grain control of the layer rendering order, a z-index can be defined for each layer. Layers with a higher z-index are rendered on top of layers with a lower z-index. The exceptions are the background layer, which is always rendered first, and the feature layer, which is rendered with a z-index of 100, by default.

The visibility of layers can be toggled, which can be an alternative to adding and removing them, dynamically. For map overlays, a layer can be configured with a lowered opacity so that the background layer is still semi-visible below the overlay. Some map services may provide map data with a lowered opacity by default.

The following example demonstrates how to replace the background layer, how to add several overlays to the map, and how to control their visibility:

Open in a
new tab
// Replace background layer when option changes
backgroundLayerGroup.addValueChangeListener(e -> {
    LayerOption selectedOption = e.getValue();
    XYZSource.Options sourceOptions = new XYZSource.Options();
    sourceOptions.setUrl(selectedOption.getUrl());
    sourceOptions
            .setAttributions(List.of(selectedOption.getAttributions()));
    sourceOptions.setAttributionsCollapsible(false);
    XYZSource source = new XYZSource(sourceOptions);
    TileLayer layer = new TileLayer();
    layer.setSource(source);
    map.setBackgroundLayer(layer);
});

...

// Add all overlay layers at once, make them invisible initially
List.of(PRECIPITATION_LAYER, AIR_TEMPERATURE_LAYER, WIND_SPEED_LAYER)
        .forEach(option -> {
            XYZSource.Options sourceOptions = new XYZSource.Options();
            sourceOptions.setUrl(option.getUrl());
            sourceOptions
                    .setAttributions(List.of(option.getAttributions()));
            sourceOptions.setAttributionsCollapsible(false);
            XYZSource source = new XYZSource(sourceOptions);
            TileLayer layer = new TileLayer();
            layer.setSource(source);
            layer.setVisible(false);

            map.addLayer(layer);
            overlayLayerMap.put(option, layer);
        });

...

// Toggle visibility of overlay layer when option changes
overlayLayerGroup.addValueChangeListener(e -> {
    LayerOption selectedOption = e.getValue();
    // Make previously selected layer invisible
    if (selectedOverlayLayer != null) {
        selectedOverlayLayer.setVisible(false);
    }
    // Get next selected layer
    selectedOverlayLayer = overlayLayerMap.get(selectedOption);
    // Make selected layer visible, unless it's the none option
    if (selectedOverlayLayer != null) {
        selectedOverlayLayer.setVisible(true);
    }
});

Markers

Markers can be displayed on top of a map to show points of interest, such as addresses, buildings, vehicles, or any other entity. A marker is defined by a coordinate and an icon. Icons can be configured as either a URL or a StreamResource. If no custom icon is provided, the marker uses a default icon.

By default, map coordinates such as a marker’s location are specified in EPSG:4326 projection, also known as latitude and longitude, unless a custom user projection is configured. See Coordinate Systems for more information.

Open in a
new tab
// For Vaadin 23.1, use Coordinate.fromLonLat to create coordinates
// from longitude and latitude
Coordinate vaadinHqCoordinates = new Coordinate(22.29985, 60.45234);
Coordinate germanOfficeCoordinates = new Coordinate(13.45489, 52.51390);
Coordinate usOfficeCoordinates = new Coordinate(-121.92163, 37.36821);

// Add marker for Vaadin HQ, using default marker image
MarkerFeature vaadinHq = new MarkerFeature(vaadinHqCoordinates);
map.getFeatureLayer().addFeature(vaadinHq);

// Add marker for Vaadin office in Germany, using image from URL
Icon.Options germanFlagIconOptions = new Icon.Options();
germanFlagIconOptions.setSrc("images/german_flag.png");
Icon germanFlagIcon = new Icon(germanFlagIconOptions);
MarkerFeature germanOffice = new MarkerFeature(germanOfficeCoordinates,
        germanFlagIcon);
map.getFeatureLayer().addFeature(germanOffice);

// Add marker for Vaadin office in the US, using image from a
// StreamResource
StreamResource streamResource = new StreamResource("us-flag.png",
        () -> getClass().getResourceAsStream(
                "/META-INF/resources/images/us-flag.png"));
Icon.Options usFlagIconOptions = new Icon.Options();
usFlagIconOptions.setImg(streamResource);
Icon usFlagIcon = new Icon(usFlagIconOptions);
MarkerFeature usOffice = new MarkerFeature(usOfficeCoordinates,
        usFlagIcon);
map.getFeatureLayer().addFeature(usOffice);
Note
Performance considerations

When using custom icons, ensure that you create only one icon instance per custom image that you want to use. For example, when adding multiple markers that use the same image, it’s sufficient to create one icon instance and use that for all markers. Creating a separate icon instance for each marker can increase memory usage and degrade performance in the browser.

Events

The Map component provides several events that can be used to make a map interactive. Currently, the following events are supported:

Event Description

View Move End

Triggered after the user has changed the viewport, regardless of the input method. The event is triggered only after the user has finished manipulating the viewport. For example, it’s triggered after letting go of the mouse button after a mouse drag action.

The event contains details about the current viewport, such as the center, the zoom level, and the current bounding box, the extent of the viewport.

Map Click

Triggered when the user clicks on the map. The event contains information about the clicked coordinates and other details of the mouse event. It also contains a list of all markers at that location to distinguish whether the click occurred on the map itself, or on a marker.

Feature Click

Triggered when the user clicks on a marker. The event contains information about the clicked marker and other details of the mouse event. If there are overlapping markers, the event is fired only for the top-level marker at that location.

The term feature refers to geographical features in a general sense. For now, Map only supports markers as geographical features, so these are equivalent.

The following example demonstrates how to make use of the events:

Open in a
new tab
map.addViewMoveEndEventListener(e -> {
    Coordinate center = e.getCenter();
    Extent extent = e.getExtent();
    String info = "";
    info += String.format("Center = { x: %s, y: %s }%n", center.getX(),
            center.getY());
    info += String.format("Zoom   = %s%n", e.getZoom());
    info += String.format("Extent = { left: %s, top: %s,%n",
            extent.getMinX(), extent.getMinY());
    info += String.format("           right: %s, bottom: %s }",
            extent.getMaxX(), extent.getMaxY());
    viewEventInfo.setValue(info);
});

map.addClickEventListener(e -> {
    Coordinate coordinates = e.getCoordinate();
    String info = String.format("Coordinates = { x: %s, y: %s }",
            coordinates.getX(), coordinates.getY());
    mapClickInfo.setValue(info);
});

map.addFeatureClickListener(e -> {
    MarkerFeature feature = (MarkerFeature) e.getFeature();
    Coordinate coordinates = feature.getCoordinates();
    // Get city entity for event marker,
    // see remaining example on how the markers are set up
    City city = cityLookup.get(feature);
    String info = "";
    info += String.format("City        = %s%n", city.getName());
    info += String.format("Coordinates = { x: %s, y: %s }",
            coordinates.getX(), coordinates.getY());
    featureClickInfo.setValue(info);
});

Coordinate Systems

The default coordinate system, or projection, for all coordinates passed to or received from the component is EPSG:4326, also referred to as GPS coordinates or latitude and longitude. This is called the user projection as it affects all of the coordinates that the user of the component, in this case the developer, is working with. That means when setting coordinates, such as for the viewport or for a marker, coordinates must be specified in EPSG:4326 by default. Coordinates received from events are guaranteed to be in that projection.

Internally, the component converts all of the coordinates into the projection that’s used by the map’s view. This is called the view projection. The default view projection is EPSG:3857, also known as Web Mercator Projection.

Changing the User Projection

The user projection can be changed, for example when working with coordinates that aren’t in the EPSG:4326 projection. Out of the box, the component only has support for the EPSG:4326 and EPSG:3857 projections. However, the component allows defining custom projections. As mentioned above, changing the user projection affects all coordinates. Using coordinates with different projections isn’t supported.

Example for setting a different user projection
// Set user projection to EPSG:3857
Map.setUserProjection("EPSG:3857");

// Create a map, center viewport on New York using
// coordinates in EPSG:3857 projection
Map map = new Map();
map.setCenter(new Coordinate(-8235375.352932, 4967773.457877));
map.setZoom(10);
Note
User Projection Scope

The user projection setting is valid for the lifetime of the current browser page. This means it stays defined when navigating using the router, but not when doing a hard location change, or reloading the page. In practice, it’s advisable to set the user projection on every page where it’s used.

The user projection affects all maps on the browser page, and should be set before creating any maps.

Defining Custom Projections

Custom projections can be defined when working with coordinates that are in neither EPSG:4326 nor EPSG:3857 projection. Defining a custom projection requires a name, which can later be referenced, as well as a projection definition in the Well Known Text (WKT) format. epsg.io is a handy resource for looking up WKT definitions of projections, as well as converting coordinates between specific projections. After a custom projection has been defined, it can be used as either user projection or view projection.

Example for defining a custom projection
// Define EPSG:3067, which is a projection specifically for use in Finland
String wkt = ""
    + "PROJCS[\"ETRS89 / TM35FIN(E,N)\",\n"
    + "    GEOGCS[\"ETRS89\",\n"
    + "        DATUM[\"European_Terrestrial_Reference_System_1989\",\n"
    + "            SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
    + "                AUTHORITY[\"EPSG\",\"7019\"]],\n"
    + "            TOWGS84[0,0,0,0,0,0,0],\n"
    + "            AUTHORITY[\"EPSG\",\"6258\"]],\n"
    + "        PRIMEM[\"Greenwich\",0,\n"
    + "            AUTHORITY[\"EPSG\",\"8901\"]],\n"
    + "        UNIT[\"degree\",0.0174532925199433,\n"
    + "            AUTHORITY[\"EPSG\",\"9122\"]],\n"
    + "        AUTHORITY[\"EPSG\",\"4258\"]],\n"
    + "    PROJECTION[\"Transverse_Mercator\"],\n"
    + "    PARAMETER[\"latitude_of_origin\",0],\n"
    + "    PARAMETER[\"central_meridian\",27],\n"
    + "    PARAMETER[\"scale_factor\",0.9996],\n"
    + "    PARAMETER[\"false_easting\",500000],\n"
    + "    PARAMETER[\"false_northing\",0],\n"
    + "    UNIT[\"metre\",1,\n"
    + "        AUTHORITY[\"EPSG\",\"9001\"]],\n"
    + "    AXIS[\"Easting\",EAST],\n"
    + "    AXIS[\"Northing\",NORTH],\n"
    + "    AUTHORITY[\"EPSG\",\"3067\"]]";
Map.defineProjection("EPSG:3067", wkt);

// Set user projection to EPSG:3067
Map.setUserProjection("EPSG:3067");

// Create a map, change view projection to EPSG:3067 as well
Map map = new Map();
map.setView(new View("EPSG:3067"));

// Center viewport on Helsinki using
// coordinates in EPSG:3067 projection
map.setCenter(new Coordinate(385725.63, 6671616.89));
map.setZoom(10);
Note
Custom projection scope

Custom projections are valid for the lifetime of the current browser page. This means they stay defined when navigating using the router, but not when doing a hard location change, or reloading the page. In practice, it’s advisable to define projections on every page where they are used.

Custom projections must be defined before using them as either user projection or view projection.

Breaking Changes since 23.1

In Vaadin 23.2, the default coordinate system has been changed to EPSG:4326, also referred to as GPS coordinates, or latitude and longitude. Since this documentation has already been updated to 23.2, all documentation sections refer to the new coordinate system. Examples have been adapted to create coordinates using latitude and longitude.

If you are still using Vaadin 23.1, the default coordinate system is EPSG:3857. All coordinates provided to the map must be in that projection. If you want to create coordinates from latitude and longitude in 23.1, use the static Coordinate.fromLonLat(longitude, latitude) helper. You can adapt the examples from this documentation to work with 23.1 by changing code that constructs coordinates:

new Coordinate(longitude, latitude)
Coordinate.fromLonLat(longitude, latitude)

Theme Variants

Borderless

By default, Map has a visible, rounded border. The border can be removed by using the borderless theme variant.

Open in a
new tab
map.addThemeVariants(MapVariant.BORDERLESS);

Usage with Vaadin 23.0 and 23.1

To use Map with Vaadin 23.0 or 23.1, you must enable with the mapComponent feature flag.

See Feature Flags for more information.

04C74C61-682E-40A8-B152-BEBF1C38C49C