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?
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.
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.