1

On my map I load several GeoJSON files containing various polygons (areas). Each layer corresponds to a single file. I also created variable that aggregate sources and layers to enable a search engine which works on various parameters (type of source or features within a source), like the following:

  layers_group = [];
  layers_group.push(
    layer_australia_new_zealand_southern_indian_ocean_imma, layer_australia_new_zealand_southern_indian_ocean_cimma,
    layer_extended_southern_ocean_imma, layer_extended_southern_ocean_cimma);

source_group = [];
source_group.push(
    source_australia_new_zealand_southern_indian_ocean_imma, source_australia_new_zealand_southern_indian_ocean_cimma,
    source_extended_southern_ocean_imma, source_extended_southern_ocean_cimma);

I created a switcher to allow a change of projection between EPSG:3857 (default) and Orthographic projection (in this case South): the code basically is the following:

var circle = new ol.geom.Circle([0, 0], 6370997);
var style = new ol.style.Style({
  fill: new ol.style.Fill({
  color: "black"
  })
});
var createCircle = function(e) {
    var vectorContext = e.vectorContext;
    e.context.globalCompositeOperation = "destination-in";
    vectorContext.setStyle(style);
    vectorContext.drawCircle(circle);
    e.context.globalCompositeOperation = "source-over";
}
var viewProjSelect = document.getElementById('change-projection-button');

//Function managing projection change
function updateViewProjection() {
  var newProj = viewProjSelect.value;
  if(newProj && newProj=="ORTHO-SOUTH") {
      var newView = new ol.View({
      projection: newProj,
      center: [15,-90],
      zoom: 1,
      minZoom: 1
      });
      map.setView(newView);
          map
          .getLayers()
          .getArray()[0]
          .on('postcompose', createCircle);   
          var i;
          for (i = 0; i< source_group.length; ++i) {
              source_group[i].clear();
              source_group[i].refresh();
          }                 
  }
  else {
      var newView = new ol.View({
      projection: newProj,
      center: [0,0],
      zoom: 2,
      minZoom: 1
      });
      map
          .getLayers()
          .getArray()[0]
          .un('postcompose', createCircle);
      map.setView(newView);    
      var i;
      for (i = 0; i< source_group.length; ++i) {
        
          source_group[i].clear();
          source_group[i].refresh();
      }
  }
};
//Handle change of projection    
viewProjSelect.onchange = function() {
      updateViewProjection();
  };

With the above function I can change projection and re-map the layers according to the projection chosen. Everything works fine until I deal with the entire layer.

My problem comes when I search for a single feature within a layer. With the EPSG:3857 projection the search engine code works fine: single areas within a source group (features -> title and status) are visualized on the map with the following code

var selectedImmas = $("#immas_autocomplete").val();
    var index;
    for (index = 0; index < source_group.length; ++index){
        source_group[index].forEachFeature(function(feat){              
//if substring(selected text) exist within fetaure property('Title')
//should return any value other than -1
            if (feat.get('Title').indexOf(selectedImmas)!=-1) {
                if (feat.get('Status')) {
                    feat.setStyle(cImmaStyle);
                } else {
                    feat.setStyle(defaultStyle);    
                }                   

            document.getElementById("messageBar").innerHTML = feat.get('Region') + ': ' + selectedImmas;

            } else {
//and if doesn't exist switch back to the deafult style
            feat.setStyle(transparentStyle);
            }
            

But if I want to change the projection after having searched for a single feature, the polygon disappears. I understand that in order to show the single features when changing the projection I cannot deal in the updateViewProjection function only with the source.group[i], but I should further re-iterate the single arrays to select the single feature (feat.get('Title') for example). I tried then to perform the action present in the search engine within the updateViewProjection function, but it didn't work.

Do you have any suggestion? I am afraid I do not sufficiently know OL4 to do it by myself.

////EDIT AFTER ANSWER (SEE MY COMMENT)

I tried to add the function suggested to my code in the following way (see below), but it gives me an Uncaught TypeError: node.children is undefined. I guess I misunderstood the use of the function.

var viewProjSelect = document.getElementById('view-projection');

//Function managing projection change
function updateViewProjection() {
  var newProj = viewProjSelect.value;
  if(newProj && newProj=="ORTHO-SOUTH") {
      var newView = new ol.View({
      projection: newProj,
      center: [15,-90],
      //   center: ol.proj.fromLonLat([-97.6114, 38.8403], viewProjection),
      zoom: 1,
      minZoom: 1
      });
      map.setView(newView);
            
            map
            .getLayers().forEach(function(layer) { updateLayer(layer) })
            .getArray()[0]
            .on('postcompose', createCircle);  
            var i;
            for (i = 0; i< source_group.length; ++i) {
                source_group[i].clear();
                source_group[i].refresh();
            }
            var j;
            for (j = 0; j< source_aoi.length; ++j) {
                source_aoi[j].clear();
                source_aoi[j].refresh();
            }              

        function updateLayer(layer) {
            if (layer.getSource) {
                console.log(layer.getSource());
                var source = layer.getSource();
                if (source && source.getSource) {
                    // cluster source
                    source = source.getSource();
                }
                if (source && source.forEachFeature) {

                    source.forEachFeature(function(feature){

                        feature.getGeometry().transform(standardProjection, newProj);
                    });
                }
            }
        }
  }
};
///
//Handle change of projection

viewProjSelect.onchange = function() {
      updateViewProjection();
  };
1

Vector layers and overlays are not automatically reprojected if you change the view. This code should handle that, including going through layer groups and special handling for cluster sources (I have used it when panning a map between two UTM zones):

        map.getOverlays().forEach(function(overlay){
            if (overlay.getPosition()) {
                overlay.setPosition(ol.proj.transform(overlay.getPosition(), oldProjection, newProjection));
            }
        });

        map.getLayers().forEach(function(layer) { updateLayer(layer) });

        function updateLayer(layer) {
            if (layer.getLayers) {
                // layer group
                layer.getLayers().forEach(function(layer) { updateLayer(layer) });
            } else if (layer.getSource) {
                var source = layer.getSource();
                if (source && source.getSource) {
                    // cluster source
                    source = source.getSource();
                }
                if (source && source.forEachFeature) {
                    source.forEachFeature(function(feature){
                        feature.getGeometry().transform(oldProjection, newProjection);
                    });
                }
            }
        }

Note that if features are out of range and not projectable in the new projection the geometry will be corrupted and you will not be able to recover them if you change back to the original projection.

  • Hi I tried to include your code in my updateViewProjection: instead of having map.getLayers(), I added map.getLayers().forEach(function(layer) { updateLayer(layer) }). I then added your function updateLayer. It changes the projection but it doesn't apply anymore the circle clipping and above all it doesn't apply the transformation of polygons projection (see the link to the [test] (marinemammalhabitat.org/test/imma-eatlas)) – Elena Politi Aug 3 '20 at 16:43
  • I added an edit to my question, with the code I tried to implement upon @Mike suggestion, but the geometry of each feature is not transformed – Elena Politi Aug 3 '20 at 18:16
  • 1
    If you have already cleared and refreshed the sources there will be no reason to transform - but transforming would avoid having to reload the data. If you only want to show a single feature you could do that with a style function and only return a style for the feature you want. – Mike Aug 3 '20 at 21:06
  • Yes you are right: I adjusted the code, deleting data reloading and it works. Just one question: since the switcher works to change projection between mercator / orthographic south /orthographic north, I cannot simply use feature.getGeometry().transform(oldProjection, newProjection) . I need to 1) have a var with the chosen projection from the switcher and 2) have a var with the actual projection (it could be one of the three). How can I get the projection that I see on the screen? Using map.getProjection(); before running the script? I tried but didn't work – Elena Politi Aug 5 '20 at 10:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.