Google Maps : markers not removed as expected

Using the Google Map add-on, I want to show some markers depending on a slider position (if slider to right, show them all, if to the left, hide some of them according to some rule).
I have code (see below), but the markers are not updated as expected. When moving the slider to the right, the markers are added, but when returning left, they are not removed. It behaves as if the markers on removal are update only one by one, and so several slider movements are necessary to fully update the map.

How can I show/hide markers dynamically according to a slider position?

Full code:

package com.buluschek.distancemap;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.shared.ui.slider.SliderOrientation;
import com.vaadin.tapio.googlemaps.GoogleMap;
import com.vaadin.tapio.googlemaps.client.LatLon;
import com.vaadin.tapio.googlemaps.client.overlays.GoogleMapMarker;
import com.vaadin.ui.Slider;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings("serial")
@Theme("distancemap")
public class DistancemapUI extends UI {

    @WebServlet(value = "/*", asyncSupported = true)
    @VaadinServletConfiguration(productionMode = false, ui = DistancemapUI.class, widgetset = "com.buluschek.distancemap.widgetset.DistancemapWidgetset")
    public static class Servlet extends VaadinServlet {
    }

    private final List<GoogleMapMarker > markers = new ArrayList<GoogleMapMarker>();

    @Override
    protected void init(VaadinRequest request) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        setContent(layout);

        // Creating 20 markers at different positions
        // Marker IDs go from 0 to 20, using those as the value which we will filter
        // with the slider.
        for (int i = 0; i < 20; i++) {
            GoogleMapMarker googleMapMarker = new GoogleMapMarker("Mark " + i, new LatLon(50+(i % 3), i), false, null);
            markers.add(googleMapMarker);
            System.out.println(googleMapMarker.getId());
        }

        final GoogleMap googleMap = new GoogleMap(null, null, "english");
        googleMap.setSizeFull();
        googleMap.fitToBounds(new LatLon(53, 20), new LatLon(50, 0));
        
        // Add a slider which will allow to show / hide part of the markers
        final Slider slider = new Slider(0, 20);
        slider.setImmediate(true);
        slider.setWidth("100%");
        slider.setOrientation(SliderOrientation.HORIZONTAL);
        slider.addValueChangeListener(new Property.ValueChangeListener() {

            @Override
            public void valueChange(ValueChangeEvent event) {
                Double value = slider.getValue();

                for (GoogleMapMarker marker : markers) {
                    boolean hasMarkerAlready = googleMap.hasMarker(marker);
                    boolean shouldShow = marker.getId() < value;
                    if(shouldShow && !hasMarkerAlready){
                        System.out.println("Adding marker " + marker.getId());
                        googleMap.addMarker(marker);
                    } else if ( !shouldShow && hasMarkerAlready){
                        System.out.println("Removing marker " + marker.getId());
                        googleMap.removeMarker(marker);
                    }
                }
            }
        });
        layout.addComponent(googleMap);
        layout.addComponent(slider);
    }
}

Here is an even simpler example, using just a button to remove markers. On the screen, only one marker (the first) is removed. Expected is that all markers are removed.
Versions:
Latest Chrome browser.
Vaadin 7.4.0
googlempas add-on: 1.0.0
Tomcat 7

package com.buluschek.distancemap;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.shared.ui.slider.SliderOrientation;
import com.vaadin.tapio.googlemaps.GoogleMap;
import com.vaadin.tapio.googlemaps.client.LatLon;
import com.vaadin.tapio.googlemaps.client.overlays.GoogleMapMarker;
import com.vaadin.ui.Button;
import com.vaadin.ui.Slider;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;

@SuppressWarnings("serial")
@Theme("distancemap")
public class DistancemapUI extends UI {

    @WebServlet(value = "/*", asyncSupported = true)
    @VaadinServletConfiguration(productionMode = false, ui = DistancemapUI.class, widgetset = "com.buluschek.distancemap.widgetset.DistancemapWidgetset")
    public static class Servlet extends VaadinServlet {
    }

    private final List<GoogleMapMarker > markers = new ArrayList<GoogleMapMarker>();

    @Override
    protected void init(VaadinRequest request) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        setContent(layout);

        // Creating 20 markers at different positions
        for (int i = 0; i < 20; i++) {
            GoogleMapMarker googleMapMarker = new GoogleMapMarker("Mark " + i, new LatLon(50+(i % 3), i), false, null);
            markers.add(googleMapMarker);
        }

        final GoogleMap googleMap = new GoogleMap(null, null, "english");
        googleMap.setSizeFull();
        googleMap.fitToBounds(new LatLon(53, 20), new LatLon(50, 0));

        // Adding all markers
        for (GoogleMapMarker marker : markers) {
            googleMap.addMarker(marker);
        }

        // On button click remove all markers
        Button button = new Button("Remove markers");
        button.addClickListener(new Button.ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                for (GoogleMapMarker marker : markers) {
                    googleMap.removeMarker(marker);
                }
            }
        });
        layout.addComponent(googleMap);
        layout.addComponent(button);
    }
}

Maybe GoogleMapWidget.setMarkers(Collection) is not modifying the markeMap correctly?

        for (Marker marker : markerMap.keySet()) {
            GoogleMapMarker gMapMarker = markerMap.get(marker);
            if (!markers.contains(gMapMarker)) {
                marker.close();
                gmMarkerMap.remove(gMapMarker);
                markerMap.remove(marker);
            }
        }

I’d expect a ConcurentModificationException as we modify markerMap while iterating over it. (although I see no exceptions in my server log). I guess it should rather be: for (Iterator<Marker> it = markerMap.keySet().iterator(); it.hasNext();) { Marker marker = it.next(); GoogleMapMarker gMapMarker = markerMap.get(marker); if (!markers.contains(gMapMarker)) { marker.close(); gmMarkerMap.remove(gMapMarker); it.remove(); } }

I’m facing the same issue. Personally, I’ve got an OptionGroup in my page. Clicking over an option group shows a group of markers and a polyline in a map. When unchecking an active option, the desired action would be to remove the markers and the polyline, but however:

  • The polyline is not removed.
  • When I perform the following loop, the results are the following (considering there are 3 markers: red, green and blue):
    [list]
  • [1]
    → Check (red, green and blue markers appear, plus the polyline) and uncheck, first red marker removed.
  • [2]
    → Check (first red marker crops up) and uncheck, green marker removed.
  • [3]
    → Check (green marker crops up) and uncheck, blue marker removed
  • [4]
    → Again to [1]
    .

    [/list]

Is it a bug or something we aren’t using properly?

Thanks!

In my post
https://vaadin.com/forum#!/thread/9424662/9461876
, I believe I have found a bug which explains the behavior (in the GoogleMapWidget class).
I haven’t filed a bug report yet, as I am waiting for some confirmation or acknoledgement from Tapio.

Until the bug is fixed, would it be an alternative to use v-leaflet?

Not sure what you mean (not a vaadin expert). But what should work is removing one object at a time - removing only one marker, removing only the polyline.
I guess this means having one server roundtrip per marker/polyline removal, but maybe there’s a way to postpone the updating of the map.

I mean not using the default GoogleMap for Vaadin and using the Leaflet extensión for Vaadin.

I discovered leaflet the previous Friday and I’m gonna use it. You should take a look at it https://vaadin.com/directory#addon/v-leaflet:vaadin and at it extension for supporting other layers https://vaadin.com/directory#addon/v-leaflet-shramov-extensions

Thanks for pointing this out. It’s very interesting. Especially the different license (use on intranets) as compared to GoogleMaps.

Will try it out.

:smiley: