Search code examples
javascriptjsfjakarta-eeprimefacesprimefaces-gmap

Overriding Primefaces GMap renderer class


I'm trying to override the GMap renderer class, so I can set styles to it at renderer phase. I was setting this via js function, window.onload=function(...), but it's very ugly, because the map shows first with default style. Only after 1-2 secs that it changes the style.

That's my renderer class:

public class MyGMapRenderer extends GMapRenderer {

@Override
protected void encodeScript(FacesContext context, GMap map) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String clientId = map.getClientId();
    String widgetVar = map.resolveWidgetVar();
    GMapInfoWindow infoWindow = map.getInfoWindow();

    startScript(writer, clientId);

    writer.write("$(function() {");

    writer.write("PrimeFaces.cw('GMap','" + widgetVar + "',{");
    writer.write("id:'" + clientId + "'");

    //Required configuration
    writer.write(",mapTypeId:google.maps.MapTypeId." + map.getType().toUpperCase());
    writer.write(",center:new google.maps.LatLng(" + map.getCenter() + ")");
    writer.write(",zoom:" + map.getZoom());

    if (!map.isFitBounds()) {
        writer.write(",fitBounds:false");
    }

    //Overlays
    encodeOverlays(context, map);

    //Controls
    if (map.isDisableDefaultUI()) {
        writer.write(",disableDefaultUI:true");
    }
    if (!map.isNavigationControl()) {
        writer.write(",navigationControl:false");
    }
    if (!map.isMapTypeControl()) {
        writer.write(",mapTypeControl:false");
    }
    if (map.isStreetView()) {
        writer.write(",streetViewControl:true");
    }

    //Options
    if (!map.isDraggable()) {
        writer.write(",draggable:false");
    }
    if (map.isDisableDoubleClickZoom()) {
        writer.write(",disableDoubleClickZoom:true");
    }

    //##### HERE THE ONLY LINE I ADDED ####
    writer.write(",styles:[{\"stylers\":[{hue:\"#0077ff\"}]}]");


    //Client events
    if (map.getOnPointClick() != null) {
        writer.write(",onPointClick:function(event) {" + map.getOnPointClick() + ";}");
    }

    /*
     * Behaviors
     * - Adds hook to show info window if one defined
     * - Encodes behaviors
     */
    if (infoWindow != null) {
        Map<String, List<ClientBehavior>> behaviorEvents = map.getClientBehaviors();
        List<ClientBehavior> overlaySelectBehaviors = behaviorEvents.get("overlaySelect");
        for (ClientBehavior clientBehavior : overlaySelectBehaviors) {
            ((AjaxBehavior) clientBehavior).setOnsuccess("PF('" + widgetVar + "').openWindow(data)");
        }
    }

    encodeClientBehaviors(context, map);

    writer.write("});});");

    endScript(writer);
}
}

faces-config.xml:

<render-kit>
    <renderer>
        <component-family>org.primefaces.component</component-family>
        <renderer-type>org.primefaces.component.GMapRenderer</renderer-type>
        <renderer-class>br.com.carona.mb.MyGMapRenderer</renderer-class>
    </renderer>
</render-kit>

Other observation is that I made a workaround to prevent that ugly flash by redrawing all the map when updating it via ajax. So I'm adding and manipulating each marker from backing bean via an combination of javascript, remoteCommand and inputHidden. It's working very well.

The only problem is when the overlay select event is fired:

var markers = new Array();
 function loadMarks(){
 for(var i=0;markers.length>i; i++){
  markers[i].setMap(null);
 }


markers = new Array();
var marksJSON=document.getElementById('form:marks').value;
var marksArray= JSON.parse(pontosStr);
bounds = new google.maps.LatLngBounds();
for (var i = 0;pontos.length>i; i++) {
    var ponto = pontos[i];
    var marker= new google.maps.Marker(
    {
        position: new google.maps.LatLng(ponto.lat, ponto.lon),
        icon: ponto.icon,
        id: ponto.id,
        draggable: ponto.draggable
    });

    marker.setMap(wmap.getMap());
    bounds.extend(marker.getPosition());

    //THAT DON'T WORK ANYMORE
    google.maps.event.addListener(marker, 'click', function(event) {
         wmap.fireOverlaySelectEvent(event, this);
    });  


    //Drag is working fine
    google.maps.event.addListener(marker, 'dragend', function(event) {
        wmap.fireMarkerDragEvent(event, this);
    });

    markers.push(marker);
}
var map=wmap.getMap();
var zoomChangeBoundsListener =
google.maps.event.addListener(map, 'bounds_changed', function(event) {
    google.maps.event.removeListener(zoomChangeBoundsListener);
    map.setZoom( Math.min( 17, map.getZoom() ) );
});
wmap.getMap().fitBounds(bounds);
}

My map:

 <p:gmap id="gmap"  widgetVar="wmap" mapTypeControl="false" fitBounds="true" center="-18.57904130, -46.51830770" model="#{procuraRotaMB.mapModel}" zoom="14" type="ROADMAP" style="width:700px;height:600px">  
                    <p:ajax event="pointSelect" listener="#{procuraRotaMB.onPointSelect}" update=":form:marks" oncomplete="setupMarks();" />  
                    <p:ajax event="markerDrag" listener="#{procuraRotaMB.onMarkerDrag}" update=":formProcurar:pontos" oncomplete="setupMarks();" />
                    <p:ajax event="overlaySelect" listener="#{procuraRotaMB.onMarkerSelect}" update=":form:destinoRota,:form:infoW" oncomplete="setupDestiny();"/>
                    <p:gmapInfoWindow id="infoW"> 
                            ...
                    </p:gmapInfoWindow>
</p:gmap>

Edited:

I just found out that the problem actually is in the InfoWindow. When I remove it everything works normally.


Solution

  • The error was a divergence between the source code and the JAR, in GMapRenderer class. More precisely, in the line where the behaviors are written, in the encodeScript method.

    I already posted the issue at primefaces forum.