[GIS] OpenLayers vector does not draw (or re-draw) on zoom level change or layerswitcher off/on

javascriptopenlayers-2vector

Here is the full code (I'll highlight the important parts after):

jQuery(document).ready(function($) {

// =========================================================================================================================================
// -----------------------------------------------------------------------------------------------------------------------------------------
//      DEFINE THE OPENLAYERS MAP
// -----------------------------------------------------------------------------------------------------------------------------------------
// =========================================================================================================================================

    //var pathArray = window.location.href.split( '/' );
    //var base_url = pathArray[0] + '://' + pathArray[2];

    // Base URL (Modified by provisioning script)
    var base_url = 'http://192.168.111.222'

    // Set up URL's
    var arctic_wms = base_url.concat('/geoserver/arctic/wms');
    var arctic_wfs = base_url.concat('/geoserver/arctic/wfs');

    // User the OpenLayers ProxyHost
    OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";

    // Define OpenLayers click Control
    OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {                
                    defaultHandlerOptions: {
                        'single': true,
                        'double': false,
                        'pixelTolerance': 0,
                        'stopSingle': false,
                        'stopDouble': false
                    },

                    initialize: function(options) {
                        this.handlerOptions = OpenLayers.Util.extend(
                            {}, this.defaultHandlerOptions
                        );
                        OpenLayers.Control.prototype.initialize.apply(
                            this, arguments
                        ); 
                        this.handler = new OpenLayers.Handler.Click(
                            this, {
                                'click': this.trigger
                            }, this.handlerOptions
                        );
                    }, 

                    trigger: function(e) {
                        var lonlat = map.getLonLatFromPixel(e.xy);
                        // Create the json_string for frames/get/closest
                        json_string = '{ "type": "Feature", "properties": { "location": "arctic", "x":' + lonlat.lon + ', "y": ' + lonlat.lat + ', "season_names": [ "" ] } }';

                        // Make the ajax call
                        $.ajax({
                            url: base_url.concat('/ops/frames/get/closest'),
                            type: "POST",
                            data: ({app:'rds',data:json_string}),
                            success: function(response){click_alert(response);},
                            error: function(){alert('Error creating popup');}});
                    }
                });

    // DEFINE OpenLayers MAP Options
    var options = {
        maxExtent: new OpenLayers.Bounds(-1500000,-4000000,1500000,0),
        units: 'm',
        projection: "EPSG:3413",

    // Add controls to the map
    controls: [new OpenLayers.Control.Navigation(),
        new OpenLayers.Control.ZoomBox(),
        new OpenLayers.Control.PanZoomBar(),
        new OpenLayers.Control.MousePosition({prefix: '<a target="_blank" ' +'href="http://spatialreference.org/ref/epsg/3413/">' +'EPSG:3413</a>: '}),
        new OpenLayers.Control.ScaleLine(),
        new OpenLayers.Control.LayerSwitcher({'ascending':false})]};

    // DEFINE MAP OBJECT AND POPUP VARIABLE
    var map = new OpenLayers.Map('map',options);

    // ADD AND ACTIVATE CLICK
    var click = new OpenLayers.Control.Click();
    map.addControl(click);
    click.activate();

    // DEFINE WMS LAYERS FOR MAP
    var grn_coast = new OpenLayers.Layer.WMS("Greenland Coastline",arctic_wms,{layers: 'arctic:greenland_coastline'});
    var grn_nat_90 = new OpenLayers.Layer.WMS("Greenland Natural 90m",arctic_wms,{layers: 'arctic:greenland_natural_90m'});
    var grn_bw_45 = new OpenLayers.Layer.WMS("Greenland BW 45m",arctic_wms,{layers: 'arctic:greenland_bw_45m'});
    var rds_fl = new OpenLayers.Layer.WMS("Radar Depth Sounder Flightlines",arctic_wms,{layers: 'arctic:arctic_rds_line_paths',transparent:true,isBaseLayer:false});
    var accum_fl = new OpenLayers.Layer.WMS("Accumulation Radar Flightlines",arctic_wms,{layers: 'arctic:arctic_accum_line_paths',transparent:true,isBaseLayer:false},{visibility:false});
    var snow_fl = new OpenLayers.Layer.WMS("Snow Radar Flightlines",arctic_wms,{layers: 'arctic:arctic_snow_line_paths',transparent:true,isBaseLayer:false},{visibility:false});
    var kuband_fl = new OpenLayers.Layer.WMS("KU Band Radar Flightlines",arctic_wms,{layers: 'arctic:arctic_kuband_line_paths',transparent:true,isBaseLayer:false},{visibility:false});
    var polybound = new OpenLayers.Layer.Vector("Polygon Search Boundary",{'displayInLayerSwitcher':false});
    var selectLine = new OpenLayers.Layer.Vector("Selected Line Vector",{'displayInLayerSwitcher':false});

    // ADD DRAWING CONTROLS TO THE MAP
    drawControls = {polygon: new OpenLayers.Control.DrawFeature(polybound,OpenLayers.Handler.Polygon)};
    for(var key in drawControls) {map.addControl(drawControls[key]);};

    // STORE PROJ4 PROJECTIONS
    var wgs = new Proj4js.Proj('EPSG:4326');
    var ups = new Proj4js.Proj('EPSG:3413');

        // Deactivate drawing on double-click
        drawControls['polygon'].events.register("featureadded",' ',endDraw);
            function endDraw(data){

                // Deactivate
                drawControls['polygon'].deactivate(); 

                // Transform the polygon to WGS84 (EPSG:4326)
                var polybound_wgs  = polybound.features[0].geometry.transform(new OpenLayers.Projection("EPSG:3413"),new OpenLayers.Projection("EPSG:4326"));

                // Get the extent/vertices of the polygon drawn
                var polyExt = polybound_wgs.getBounds();
                var poly = polybound_wgs.getVertices();

                // Set the coordinate boxes to the polygon bounds
                max_lat.value = polyExt.top; min_lat.value = polyExt.bottom; max_lon.value = polyExt.right; min_lon.value = polyExt.left;

            };

        // Clear any polygons on re-activation of draw
        drawControls['polygon'].events.register("activate",' ',clearLayer);
            function clearLayer(data){polybound.removeAllFeatures();};

    // ADD LAYERS TO MAP AND ZOOM TO MAP EXTENT
    map.addLayers([grn_coast,grn_nat_90,grn_bw_45,rds_fl,accum_fl,snow_fl,kuband_fl,polybound,selectLine]);
    map.zoomToMaxExtent();

// =========================================================================================================================================
// -----------------------------------------------------------------------------------------------------------------------------------------
//      TOOLS FOR THE BROWSER
// -----------------------------------------------------------------------------------------------------------------------------------------
// =========================================================================================================================================


$('#draw_bound').click(function() {
    alert("POLYGON DRAWING INSTRUCTIONS:\n\nLeft-Click to add a vertex to your polygon.\nDouble-click to end drawing.");

    // Activate The Polygon Drawing Tool
    drawControls['polygon'].activate();
});

$('#clear_bound').click(function() {
    polybound.removeAllFeatures();
});

$('#clear_coords').click(function() {
    max_lat.value = ""; min_lat.value = ""; max_lon.value = ""; min_lon.value = "";
});

$('#clear_frame').click(function() {
    selectLine.removeAllFeatures();
    if (typeof popup != 'undefined'){map.removePopup(popup);};
});

$('#get_csv').click(function() {

    document.getElementById("status").innerHTML = "<h3>STATUS: GENERATING CSV</h3>";

    // Check if max_lat,min_lat,max_lon,min_lon are empty
    if (max_lat.value == "" || min_lat.value == "" || max_lon.value == "" || min_lon.value == ""){
        alert('Please enter coordinates or "Draw Boundary" to get CSV');document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>";}

    else{

        alert('Your CSV is being generated. A download will pop-up when the file is ready. Make sure your pop-up blocker is disabled.');

        // Construct the bound polygon 'POLYGON((min_lon min_lat,min_lon max_lat,max_lon max_lat,min_lon min_lat,min_lon min_lat))'
        var mla = min_lat.value; var mlo = min_lon.value; var mala = max_lat.value; var malo = max_lon.value;
        var bound_str = ("POLYGON(("+mlo+" "+mla+","+mlo+" "+mala+","+malo+" "+mala+","+malo+" "+mla+","+mlo+" "+mla+"))");

        // Check if polygon string from draw exists (if so overwrite bound_str)
        if (typeof polybound_wgs != 'undefined' && polybound_wgs != ""){bound_str = polybound_wgs;};

        // Construct JSON string
        var json_string = JSON.stringify({'bound':bound_str,location:'arctic'});

        // Call the get csv django view and return the response
        $.ajax({
            url: base_url.concat('/ops/layer_points/get/csv'),
            type: "POST",
            data: ({app:$('#system').val(),data:json_string}),
            success: function(response){csv_alert(response);},
            error: function(){alert('Error creating CSV. Unknown Error.'); document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>";}});
    };
});

function csv_alert(response){
    if (response.status == 0) {alert(response.data); document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>"; return;};
    alert('Your CSV is ready for download, a new window will open. Please save the link, your csv will be available on the server for 7 days.');
    document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>";
    return window.open(response.data,'CSV Download Ready','width=600,height=200');
}

function click_alert(response){

    // Clear the previously selected line
    selectLine.removeAllFeatures();

    // Clear any existing popups
    if (typeof popup != 'undefined'){map.removePopup(popup);};

    // Parse the response from django
    data = jQuery.parseJSON(response.data);

    // Create the vector feature and plot the vector
    var points = new Array();
    for (idx=0;idx<=data.x.length;idx++){
        points.push(new OpenLayers.Geometry.Point(data.x[idx],data.y[idx]))
        };
    var line = new OpenLayers.Geometry.LineString(points);
    var style = {strokeColor: '#FF0000',strokeWidth: 5};
    var linefeature = new OpenLayers.Feature.Vector(line,null,style);
    selectLine.addFeatures([linefeature]);

    // weird thing that makes it work...
    //data = data;

    popup = new OpenLayers.Popup.FramedCloud("Selected Frame", //id
        new OpenLayers.LonLat(data.x[0],data.y[0]), //lonlat
        null, //contentSize
        "<div style='font-size:.8em'>Season: " + data.season_name +"<br>Frame: " + data.frame_name+"</div>", //contentHTML
        null, //closeBox
        true); //closeBoxCallback

    map.addPopup(popup);

    // Check for NO ECHOGRAM ONLINE
    if (data.echogram_url == 'NO ECHOGRAM ONLINE'){alert('No echogram to display in pop-up. Sorry.'); return;};

    // Return a new window with the echogram
    return window.open(data.echogram_url,'Echogram Image');
}

$('#get_kml').click(function() {

    document.getElementById("status").innerHTML = "<h3>STATUS: GENERATING KML</h3>";

    // Check if max_lat,min_lat,max_lon,min_lon are empty
    if (max_lat.value == "" || min_lat.value == "" || max_lon.value == "" || min_lon.value == ""){
        alert('Please enter coordinates or "Draw Boundary" to get KML');document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>";}

    else{

        alert('Your KML is being generated. A download will pop-up when the file is ready. Make sure your pop-up blocker is disabled.');

        // Construct the bound polygon 'POLYGON((min_lon min_lat,min_lon max_lat,max_lon max_lat,min_lon min_lat,min_lon min_lat))'
        var mla = min_lat.value; var mlo = min_lon.value; var mala = max_lat.value; var malo = max_lon.value;
        var bound_str = ("POLYGON(("+mlo+" "+mla+","+mlo+" "+mala+","+malo+" "+mala+","+malo+" "+mla+","+mlo+" "+mla+"))");

        // Check if polygon string from draw exists (if so overwrite bound_str)
        if (typeof polybound_wgs != 'undefined' && polybound_wgs != ""){bound_str = polybound_wgs;};

        // Construct JSON string
        var json_string = JSON.stringify({'bound':bound_str,location:'arctic'});

        // Call the get kml django view and return the response
        $.ajax({
            url: base_url.concat('/ops/layer_points/get/kml'),
            type: "POST",
            data: ({app:$('#system').val(),data:json_string}),
            success: function(response){kml_alert(response);},
            error: function(){alert('Error creating KML. Unknown Error.'); document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>";}});
    };
});

function kml_alert(response){
    if (response.status == 0) {alert(response.data); document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>"; return;};
    alert('Your KML is ready for download, a new window will open. Please save the link, your kml will be available on the server for 7 days.');
    document.getElementById("status").innerHTML = "<h3>STATUS: NORMAL</h3>";
    return window.open(response.data,'KML Download Ready','width=600,height=200');
}

$('#get_mat').click(function() {alert('MAT download in development.');});
$('#max_lat').blur(function() {
    if (max_lat.value > 90){alert("Latitude must be between -90 and 90")};
});

$('#min_lat').blur(function() {
    if (min_lat.value < -90){alert("Latitude must be between -90 and 90")};
});

$('#min_lon').blur(function() {
    if (min_lon.value < -180){alert("Longitude must be between -180 and 180")};
});
$('#max_lon').blur(function() {
    if (max_lon.value > 180){alert("Longitude must be between -180 and 180")};
});
});

So I have a button on an html page that activates the drawing of a polygon on a vector layer. When a feature is added the drawing is halted. When the button to draw is clicked again the features are removed, and the cycle starts over.

Here is the layer:

var polybound = new OpenLayers.Layer.Vector("Polygon Search Boundary" {'displayInLayerSwitcher':false});

Here is adding the drawing controls:

drawControls = {polygon: new OpenLayers.Control.DrawFeature(polybound,OpenLayers.Handler.Polygon)};
for(var key in drawControls) {map.addControl(drawControls[key]);};

Here is the function that activates drawing:

$('#draw_bound').click(function() {
    alert("POLYGON DRAWING INSTRUCTIONS:\n\nLeft-Click to add a vertex to your polygon.\nDouble-click to end drawing.");

    // Activate The Polygon Drawing Tool
    drawControls['polygon'].activate();
});

This clears any existing features on activation:

// Clear any polygons on re-activation of draw
drawControls['polygon'].events.register("activate",' ',clearLayer);
    function clearLayer(data){polybound.removeAllFeatures();};

What happens that I cannot figure out is this:

  1. User clicks the draw button and draws a polygon
  2. User double clicks and drawing is finished, all is well
  3. ERROR HERE: User zooms in/out or unchecks-rechecks the layer in the layer switcher and the polygon they drew disappears. The object still exists, it's just not visible.

Any ideas?

Best Answer

I ran into a similar problem. Most probably, the problem is the "transform" function that you call here:

// Transform the polygon to WGS84 (EPSG:4326)
var polybound_wgs  = polybound.features[0].geometry.transform(new OpenLayers.Projection("EPSG:3413"),new OpenLayers.Projection("EPSG:4326"));

It not only assigns the transformed geometry to polybound_wgs but it also transforms the original geometry in polybound. So when you zoom out, the feature(s) in polybound get redrawn somewhere else (since the projection has changed from EPSG:3413 to EPSG:4326) OR they do not get rendered at all and are dumped into polybound.unrenderedFeatures.

This is what I did. I cloned the features on polybound layer and then transformed them leaving the original polybound features intact. Alternatively, we can transform the features back to EPSG:4326 when we are done with it (which in this case, will be after assigning the transformed geometry to polybound_wgs)