I'm developing an app with JSF and PrimeFaces. I have a PrimeFaces Gmap component on a page. I want to allow the user to draw a map polygon on screen, simply clicking each vertex, and see how the polygon constructs on the fly with each click. And also receive each point data in the Backing Bean, so I can store/persist the data in the database.
I followed the logic "For each click I want to update the map, and the model in the backing bean", so I did put update="@this" in the <p:ajax> tag in the <p:gmap> component. Problem is, making so, the whole Gmap component totally reloads, and loses its position, zoom and center. Resetting to its init values. This makes the draw operation extremely problematic because user has to zoom and pan to the zone where the polygon is wanted to be drawn, with each click.
I need the Gmap to update without totally reload it. I know the solution involves JS, sadly I'm not very expert in that language.
I made a Minimal reproducible example.
JSF page:
<h:head>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=true"></script>
</h:head>
<h:body>
<h:form id="frmMap2">
<p:gmap center="41.381542, 2.122893"
zoom="15"
type="HYBRID"
style="width:100%;height:400px"
model="#{testMapBean.polygonModel}">
<p:ajax event="pointSelect"
listener="#{testMapBean.onPointSelect}"
update="@this"/>
</p:gmap>
</h:form>
</h:body>
The backing bean (View Scoped):
@Named(value = "testMapBean")
@ViewScoped
public class TestMapBean implements Serializable {
private MapModel polygonModel;
private Polygon polygon;
public TestMapBean()
{
}
@PostConstruct
public void init()
{
polygonModel = new DefaultMapModel();
polygon = new Polygon();
polygon.setStrokeColor("#FF9900");
polygon.setFillColor("#FF9900");
polygon.setStrokeOpacity(0.7);
polygon.setFillOpacity(0.7);
polygonModel.addOverlay(polygon);
}
public void onPointSelect(PointSelectEvent event)
{
LatLng latlng = event.getLatLng();
polygon.getPaths().add(latlng);
}
// public getters and setters omitted for brevity...
I'm using: JSF 2.3 (mojarra), Primefaces 10.0, Wildfly 26.1.
EDIT
Finally made it., for anyone interested, this is the code:
View:
<h:head>
<script type="text/javascript"
src="https://maps.google.com/maps/api/js?sensor=true"></script>
<script type="application/javascript">
var map;
var pl;
function initbs()
{
// Get map through the PF widget
map = PF('wmaptest').map;
// Create Polygon
pl = new google.maps.Polygon({
strokeColor: "#777777",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
});
}
// Have a function to set coordinates to the line
function drline(coords)
{
// Add the (empty) line to the map
pl.setMap(map);
pl.setPath(coords);
}
</script>
</h:head>
<h:body>
<h:form id="frmMap2">
<p:gmap widgetVar="wmaptest"
center="41.381542, 2.122893"
zoom="15"
type="ROADMAP"
style="width:100%;height:800px">
<p:ajax event="pointSelect"
listener="#{testMapBean.onPointSelect}"/>
</p:gmap>
</h:form>
</h:body>
Bean:
@Named(value = "testMapBean")
@ViewScoped
public class TestMapBean implements Serializable {
private Set<LatLng> latLngList = new HashSet<LatLng>();
public TestMapBean()
{
}
@PostConstruct
public void init()
{
PrimeFaces.current().executeInitScript("initbs()");
}
public void drawLine()
{
String str = latLngList.stream()
.map(this::toJavaScript)
.collect(Collectors.joining(",", "drline([", "])"));
PrimeFaces.current().executeScript(str);
}
public String toJavaScript(LatLng latLng) {
return "{lat:" + latLng.getLat() + ",lng:" + latLng.getLng() + "}";
}
public void onPointSelect(PointSelectEvent event)
{
LatLng latlng = event.getLatLng();
latLngList.add(latlng);
drawLine();
}
public Set<LatLng> getLatLngList() {
return latLngList;
}
public void setLatLngList(Set<LatLng> latLngList) {
this.latLngList = latLngList;
}
}