16

There is no appropriate zoom event listener in OpenLayers v5.3 yet, but there is a workaround suggested in this ticket:

You can use this.view.instance.on('change:zoom', evt => console.log(this.view.zoom)); where view is a viewChild : @ViewChild(ViewComponent) view: ViewComponent; to detect zoom changes.

Can anyone please explain to newbies how to utilize this? How to use that code with an instance of a map view which is usually got by calling map.getView()?

5
  • 2
    That syntax is being used with Angular. You don't need a zoom change event, if the zoom changes so does the resolution, so you can use view.on('change:resolution', function() { });
    – Mike
    Commented Jan 21, 2019 at 15:22
  • 1
    The 'change:resolution' event is triggered about a dozen times for one zoom level change. The intermediate values are non-integer and the last one is always integer as far as I can see. Is there a way to catch just the final integer value?
    – yaugenka
    Commented Jan 21, 2019 at 16:04
  • Mousewheel operations can sometimes leave the map at a fractional zoom level, but if you are only interested in catching integer values you could test if (map.getView().getZoom()%1 == 0) { } inside the callback
    – Mike
    Commented Jan 21, 2019 at 16:23
  • Is it possible to the final value may be fractional?
    – yaugenka
    Commented Jan 21, 2019 at 16:56
  • In some situations it might openlayers.org/en/v4.6.5/apidoc/ol.interaction.html but you can set interactions: ol.interaction.defaults({ constrainResolution: true }), as a map option to prevent it
    – Mike
    Commented Jan 21, 2019 at 17:52

2 Answers 2

27

To hook on zoom end event is fairly simple: listen to moveend event and compare old and new zoom:

var currZoom = map.getView().getZoom();
map.on('moveend', function(e) {
  var newZoom = map.getView().getZoom();
  if (currZoom != newZoom) {
    console.log('zoom end, new zoom: ' + newZoom);
    currZoom = newZoom;
  }
});

If you want to catch zoom start, it's more complicated. I found a way but I don't like it, it's not how it should be done. I noticed that exposed method view.animate is called before any animated map event. I replaced it with my own, where I check for zoom, and then call original method:

view.origAnimate = view.animate;

view.animate = function(animateSpecs) {
  if (typeof animateSpecs.resolution !== 'undefined') {
    var currZoom = this.getZoom();
    var newZoom = this.getZoomForResolution(animateSpecs.resolution);
    if (newZoom != currZoom)) {
      console.log('zoom start, new zoom: ' + newZoom);
    }
  }
  this.origAnimate(animateSpecs);
};
1
  • Thanks, TomazicM. This solution works equally well as the one suggested by Mike in the question comments. With moveend event you have to filter map pan events where as with change:resulution you have to filer intermediate zoom change events.
    – yaugenka
    Commented Jan 22, 2019 at 14:56
8

there is a simpler way for you to do it:

map.getView().on('change:resolution', (event) => {
    console.log("zoom changed");
});
2
  • Hm this sounded like a good solution and I also expected this to work from the docs, but unfortunately this does not have an effect in my case :S
    – Merc
    Commented Mar 30, 2023 at 12:30
  • works fine with OL 7.3+ Commented Jun 13, 2023 at 12:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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