Integrate V-Leaflet vaadin add-on with platform 6.10

V-Leaflet is the Vaadin add-on based on the open source Leaflet JavaScript library for mobile-friendly interactive maps.
This step-by-step tutorial allows you to integrate addon into your Cuba Platform application. Note that your application should be based on platform version 6.10.X:

Create a new project called leaflet-demo with the root package name com.company.demo.

Create the Salesperson entity that describes an abstract salesperson.

salesperson

Because the photo attribute is an association to com.haulmont.cuba.core.entity.FileDescriptor, create a view to be able to retrieve all its attributes from the application database.

Create the entity’s editor and browser. In the view field for the editor screen, select the newly created view.

To integrate the add-on into your project you should follow these instructions. In order to find the latest compatible add-on version, go to the add-on web page and select a Vaadin 7.0+ framework support link. In our case the latest compatible version is 1.0.6:

Selection_004

Create a blank screen with XML descriptor called map-screen.xml and a controller called MapScreen.java in the com.company.demo.web.screens.map package.

Add a visual component that will be used as a container for a map to the map-screen.xml, e.g. vbox:

<layout expand="mapContainer">
    <vbox id="mapContainer" width="100%"/>
</layout>

Your controller MapScreen.java should contain these imports and the methods below:

import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.gui.components.VBoxLayout;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.haulmont.cuba.web.gui.components.WebComponentsHelper;
import com.haulmont.cuba.web.gui.components.WebFileDescriptorResource;
import com.haulmont.demo.entity.Salesperson;
import com.vaadin.server.Resource;
import com.vaadin.ui.Layout;
import org.vaadin.addon.leaflet.LLayerGroup;
import org.vaadin.addon.leaflet.LMap;
import org.vaadin.addon.leaflet.LMarker;
import org.vaadin.addon.leaflet.LOpenStreetMapLayer;
import org.vaadin.addon.leaflet.shared.Point;
import javax.inject.Inject;
import java.util.Objects;
import java.util.UUID;

initMap() creates your map, sets its default center coordinates and zoom level and adds an OSM tiles layer:

private static final double DEFAULT_LATITUDE = 53.241505;
private static final double DEFAULT_LONGITUDE = 50.221245;
private static final double ZOOM_LEVEL = 12;
...
private LMap map;
...
private void initMap() {
    map = new LMap();
    map.setZoomLevel(ZOOM_LEVEL);
    map.addLayer(new LOpenStreetMapLayer());
    map.setCenter(new Point(DEFAULT_LATITUDE, DEFAULT_LONGITUDE));
}

drawPersonMarkers() creates personMarkers LLayerGroup that contains combined map layers (markers in our case) to handle them as one in our code, refreshes salespersonsDs, then for each Salesperson creates marker that will be added to the personMarkers. Finally adds personMarkers to the map:

@Inject
private CollectionDatasource<Salesperson, UUID> salespersonsDs;
private LLayerGroup personMarkers;
...
private void drawPersonMarkers() {
    personMarkers = new LLayerGroup();

    salespersonsDs.refresh();
    for (Salesperson person: salespersonsDs.getItems()) {
        LMarker marker = createPersonMarker(person);
        personMarkers.addComponent(marker);
    }

    map.addComponent(markersGroup);
}

createPersonMarker(Salesperson person) creates LMarker object for the passed to the method Salesperson object and sets icon if a passed person has its own photo:

private LMarker createPersonMarker(Salesperson person) {
    Point personLocation = new Point(person.getLatitude(), person.getLongitude());
    LMarker marker = new LMarker(personLocation);

    Resource photoResource = getPersonPhotoResource(person);
    if (Objects.nonNull(photoResource)) {
        marker.setIcon(photoResource);
            
        Point iconSize = new Point(65, 65);  // Icon size 65x65 px
        Point iconAnchor = new Point(32, 32);  // Icon anchor at the center of the image
        
        marker.setIconSize(iconSize);
        marker.setIconAnchor(iconAnchor);
    }
    return marker;
}

getPersonPhotoResource(Salesperson person) transforms the person’s photo that is FileDescriptor object to a Vaadin Resource object needed to set marker’s icon:

private Resource getPersonPhotoResource(Salesperson person) {
    Resource photoResource = null;

    FileDescriptor photoDescriptor = person.getPhoto();
    if (Objects.nonNull(photoDescriptor)) {
        WebFileDescriptorResource fileDescriptorResource = new WebFileDescriptorResource();
        fileDescriptorResource.setFileDescriptor(photoDescriptor);
        photoResource = fileDescriptorResource.getResource();
    }

    return photoResource;
}

addMapToContainer() adds map to VBoxLayout container via vaadin Layout object:

@Inject
private VBoxLayout mapContainer;
...
private void addMapToContainer() {
    Layout layout = (Layout) WebComponentsHelper.unwrap(mapContainer);
    layout.addComponent(map);
}

Finally, you just should call the methods above from ready() hook method:

@Override
public void ready() {
    initMap();
    drawPersonMarkers();
    addMapToContainer();
}

As the result you will see the following:

map

The complete project can be found on GitHub.

2 Likes