My journey on Openlayers 2.x...


It has been, well...overwhelming.HAHA

Actually, it's quite fun and I have discovered that my codes in the previous month was so...(what's the right term?) messy and makes my head shake. 

New Me : Hey old self, that was a disaster and the ugliest code I've ever seen.
Old Me: But...it works!

Upon testing all its functionalities, lots of bugs I've found. Although it's not that major but still, a bug is a bug.

Let's talk about history...I've been working this web application in which I need to add multiple layers (flood events) for each river basin. So, my old me did this:


if (!myflag1 && "Agaton 2014" == a) {
  mainit_tubay_bldg_agaton = new OpenLayers.Layer.Vector("Mainit-Tubay Agaton 2014 Affected Buildings", {
    strategies: [new OpenLayers.Strategy.Fixed()],
    eventListeners: {
      loadend: function(a) {
        map.zoomToExtent(mainit_tubay_bldg_agaton.getDataExtent());
        $("#load_table").removeAttr("disabled", "disabled");
        $("#load_table").val("Go");
        $("#locateMe").hide();
      },
      loadstart: function(a) {
        $("#load_table").attr("disabled", "disabled").val("Loading...");
        $("#locateMe").show();
      }
    },
    projection: new OpenLayers.Projection("EPSG:4326"),
    protocol: new OpenLayers.Protocol.WFS({
      version: "1.1.0",
      url: wfs_url,
      featureType: "mainit_tubay_stats_agaton",
      featureNS: feature_ns,
      geometryName: "geometry"
    }),
    renderers: renderer,
    styleMap: new OpenLayers.StyleMap(style),
    displayInLayerSwitcher: !1
  });
  var b = $("#affectedLayer").val();
  var c = map.getLayersByName(b);
  var d = c.length;
  if (d < 1) {
    map.addLayer(mainit_tubay_bldg_agaton);
    activateControls(a);
  } else c[0].setVisibility(true);
  myflag1 = true;
  toggleStatic1("Mainit-Tubay Agaton 2014 Affected Buildings");
} else if (!myflag1 && "Seniang 2014" == a) {
  mainit_tubay_bldg_seniang = new OpenLayers.Layer.Vector("Mainit-Tubay Seniang 2014 Affected Buildings", {
    strategies: [new OpenLayers.Strategy.Fixed()],
    eventListeners: {
      loadend: function(a) {
        map.zoomToExtent(mainit_tubay_bldg_seniang.getDataExtent());
        $("#load_table").removeAttr("disabled", "disabled");
        $("#load_table").val("Go");
        $("#locateMe").hide();
      },
      loadstart: function(a) {
        $("#load_table").attr("disabled", "disabled").val("Loading...");
        $("#locateMe").show();
      }
    },
    projection: new OpenLayers.Projection("EPSG:4326"),
    protocol: new OpenLayers.Protocol.WFS({
      version: "1.1.0",
      url: wfs_url,
      featureType: "mainit_tubay_stats_seniang",
      featureNS: feature_ns,
      geometryName: "geometry"
    }),
    renderers: renderer,
    styleMap: new OpenLayers.StyleMap(style),
    displayInLayerSwitcher: !1
  });
  var b = $("#affectedLayer").val();
  var c = map.getLayersByName(b);
  var d = c.length;
  if (d < 1) {
    map.addLayer(mainit_tubay_bldg_seniang);
    activateControls(a);
  } else c[0].setVisibility(true);
  myflag1 = true;
  toggleStatic1("Mainit-Tubay Seniang 2014 Affected Buildings");
}


Which is so UGLY(this is New Me speaking...HAHA). Imagine, I need eight (8) layers for every river basin. This code will bring me to the outer space. HAHA

So, instead of doing the above code (oh just forget it! HAHA), create a function like this with a parameter(in my case; a layer name and its GeoServer name).

Adding Layers


function addVectorLayer(name, geoserver_name) {
  new_layer = new OpenLayers.Layer.Vector(name, {
    strategies: [new OpenLayers.Strategy.Fixed()],
    eventListeners: {
      loadend: function(a) {
        map.zoomToExtent(new_layer.getDataExtent());
        $("#load_table").removeAttr("disabled", "disabled");
        $("#load_table").val("Go");
        $("#locateMe").hide();
      },
      loadstart: function(a) {
        $("#load_table").attr("disabled", "disabled").val("Loading...");
        $("#locateMe").show();
      }
    },
    projection: new OpenLayers.Projection("EPSG:4326"),
    displayProjection: new OpenLayers.Projection("EPSG:3857"),
    protocol: new OpenLayers.Protocol.WFS({
      version: "1.1.0",
      url: wfs_url,
      featureType: geoserver_name,
      featureNS: feature_ns,
      geometryName: "geometry"
    }),
    renderers: renderer,
    styleMap: new OpenLayers.StyleMap(style),
    displayInLayerSwitcher: !1
  });
  var b = $("#affectedLayer").val();
  var c = map.getLayersByName(b);
  var d = c.length;
  if (d < 1) {
    map.addLayer(new_layer);
    activateControls(new_layer);
  } else {
    c[0].setVisibility(true);
  }
  toggleVectorLayer(name);
}


Few notes:

  • activateControls function is for pop up. It passes the layer object to the function and create an event like featureselected and featureunselected
  • toggleVectorLayer function hides all the vector layer. It passes the name of the newly added layer and compares it to all vector layers and if that layer did not match to the current one, set its visibility to false.
  • All layers were added only once. If you noticed, before adding the layer I have to check its length. This allows us to access that layer by its name.

Accessing layer by name


If you have a select option with the layer names you can get the layer by comparing the name to all the layer names. If it matches, then get the layer object.
But if you want to do something with the visible layer, you can do this:

var mLayers = map.getLayersByClass("OpenLayers.Layer.Vector");
for (var a = 0; a < mLayers.length; a++) {
  if (mLayers[a].getVisibility()) {
    var layerName = mLayers[a].name;
    var vlayer = map.getLayersByName(layerName);
    vlayer[0].filter = ...
    ...
  }
}

You can register events and  do dynamic filtering like this:

vlayer[0].filter = new OpenLayers.Filter.Logical({
  type: OpenLayers.Filter.Logical.AND,
  filters: [new OpenLayers.Filter.Comparison({
    type: OpenLayers.Filter.Comparison.LIKE,
    property: "bldg_name",
    value: bldg_name
  }), new OpenLayers.Filter.Comparison({
    type: OpenLayers.Filter.Comparison.LIKE,
    property: "bldg_type",
    value: bldg_type
  }), new OpenLayers.Filter.Comparison({
    type: OpenLayers.Filter.Comparison.EQUAL_TO,
    property: "gridcode",
    value: gridnumber
  })]
});
if ((get_munisipyo != "All Municipalities") && ((get_barangay === "Select Barangay") || (get_barangay === "All Barangays"))) {
  vlayer[0].filter.filters.push(
    new OpenLayers.Filter.Comparison({
      type: OpenLayers.Filter.Comparison.LIKE,
      property: "municipali",
      value: get_munisipyo
    })
  )
} else if ((get_munisipyo != "All Municipalities") && ((get_barangay != "Select Barangay") || (get_barangay != "All Barangays"))) {
  vlayer[0].filter.filters.push(
    new OpenLayers.Filter.Comparison({
      type: OpenLayers.Filter.Comparison.LIKE,
      property: "municipali",
      value: get_munisipyo
    }), new OpenLayers.Filter.Comparison({
      type: OpenLayers.Filter.Comparison.LIKE,
      property: "brgy_locat",
      value: get_barangay
    })
  )
}
vlayer[0].refresh({
  force: true
});
vlayer[0].events.register("loadend", vlayer[0], function() {
  map.zoomToExtent(vlayer[0].getDataExtent());
});

What does refresh do is, somehow like "requerying" to the service then register an event on load end and zoom to the filtered polygons.

Removing filter is pretty the same just set the filter to null.

Notes, don't add several SelectFeature controls, you can just use the function addLayer for the other layers. After all, you can assign their events individually.

That's it for now, will be posting again soon.

Not switching to Openlayers 3 anytime soon.

Popular posts from this blog

Set table width to 100% on PDF export in Datatables

Hot/Cute flat-chested Girls