21
votes

I have an OpenLayers 3 map with a base layer and a vector layer.

this.topoLayer = new ol.layer.Vector({
  source: new ol.source.Vector(),
  style: style
});

var baseLayer = new ol.layer.Tile({
    source: new ol.source.XYZ({
        url: 'http://[…]/{z}/{x}/{y}.png',
        crossOrigin: 'null'
    })
});

this.map = new ol.Map({
    target: 'map',
    layers: [baseLayer, this.topoLayer],
    view: new ol.View2D({
        center: ol.proj.transform([11.38,  48.54], this.options.markerEPSG, this.options.mapEPSG),
        zoom: 5,
    }),
});

Upon user interaction, I add and remove several features to the vector layer. Here is the function that adds a new feature:

  var feature = new ol.Feature({
        topo: topo,
        selected: false,
        geometry: new ol.geom.Point(ol.proj.transform(location, this.options.markerEPSG, this.options.mapEPSG)),
  });

  this.topoLayer.getSource().addFeatures([feature]);

After adding/removing a new feature I would like to automatically zoom and pan the map to fit my features. In the old OpenLayers API there was the getDataExtent function on vector layers to retrieve a "bounding box" around all features shown. But I wonder how to do this with the new API.

5
Right now, I store all active features in a separate array and calculate the extent from there. var coordinates = features.map(function(feature) {return feature.getGeometry().getCoordinates();}); var extent = ol.extent.boundingExtent(coordinates);SomeBdyElse
your solution in the comment works. One can call map.getView().fit(extent, map.getSize()) to adjust the map.philk

5 Answers

27
votes

In version 3.7, ol.View.fitExtent() and ol.View.fitGeometry() have been unified in a single function: fit.

So now the code is:

 var extent = myLayer.getSource().getExtent();
 map.getView().fit(extent, map.getSize());
9
votes

Based on Tyler DeWitt's answer you should be able to do something like this:

var view = yourmap.getView();
var view2D = view.getView2D();
var extent = yourlayer.getSource().getExtent();

view2D.fitExtent(extent, yourmap.getSize());

Edit: Like Tim and Stuart said the above doesn't work anymore. The following should do the trick instead:

 var extent = yourlayer.getSource().getExtent();
 map.getView().fitExtent(extent, map.getSize());
3
votes
var source = layer.getSource();
goog.events.listen(source, ol.source.VectorEventType.ADD, function(evt) {
     // taken from ol/source/vectorsource.js
     var extent = ol.extent.createEmpty();
     var geometry = null;
     var feature;
     var features = source.getFeatures().getArray();
     for (var i = 0, ii = features.length; i < ii; ++i) {
         feature = features[i];
         geometry = feature.getGeometry();
         if (!goog.isNull(geometry)) {
               ol.extent.extend(extent, geometry.getExtent());
     }
     // here you should have your extent
    }
}, false, this);

Untested.

There should be more elegant way, but I'm not sure right now, where to find it.

2
votes

Since I can't comment yet, I'll have to post another answer: Danny Hoek's answer is not correct anymore, here is the update:

var view = yourmap.getView();
var extent = yourlayer.getSource().getExtent();

view.fitExtent(extent, yourmap.getSize());

Basically that 2D prop seems to be gone.

0
votes

There is a getExtent() function on ol.source now, so I'm able to call <layer>.getSource().getExtent(). I can't figure out how to get my map to zoom to that level, however. <map>.zoomToExtent(extent) no longer exists.