Search code examples
javascripttypescriptgisopenlayersopenlayers-5

OpenLayers - Return values of getCoordinateFromPixel stay the same after calling setZoom() on map view


I have a use case where I want to determine if certain coordinates lay within the section of the view visible in the viewport. Our approach is to start by getting the coordinates of some pixels with our map's getCoordinateFromPixel method. This works, but the problem is that we also want to zoom in programmatically. We noticed that calling getCoordinateFromPixel on the map with the exact same arguments returns exactly the same thing before and after calling setZoom on the map's view. Strangely enough (?) we also noticed that when we zoom in manually in between two calls to getCoordinateFromPixel on the map, the results do change.

Take for instance this script:

import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import Feature from 'ol/Feature';

let markerView = new View({
    center: [5000, 1000],
    zoom: 2,
});

let map = new Map({
  target: 'map-container',
  layers: [
    new VectorLayer({
      source: new VectorSource({
        format: new GeoJSON(),
        url: './data/countries.json'
      }),
    })
  ],
  view: markerView
});

window.setTimeout(() => {
    console.log(JSON.stringify(map.getCoordinateFromPixel([0, 0])));
    map.getView().setZoom(5);
}, 2000);
window.setTimeout(() => {
    console.log(JSON.stringify(map.getCoordinateFromPixel([0, 0])));
}, 4000);

When one executes this is in an OpenLayers project, the closure running after 2000 ms will print the exact same thing to the console as the one running after 4000 ms, even though we have zoomed in very significantly!

I was wondering if someone knew of a workaround, a fix or just the reason for this. I have tried looking at events the map fires to maybe re-execute getCoordinateFromPixel in a handler, but I haven't found an event the map fires when we (programmatically) change the zoom.

I'll be happy to provide more details if needed.

Thanks a lot in advance,

Joshua


Solution

  • If you have the extent and map size you can easily calculate the coordinate for a pixel without relying on getCoordinateFromPixel which for some reason doesn't update immediately (it has updated by the precompose event). There is a small different in the x coordinate (about 100 meters in an 8 million extent) but not enough to be significant.

    map.getView().on(['change:resolution','change:center'], function() {
      var size = map.getSize();
      var extent = this.calculateExtent(size);
      var coordinate = [
        extent[0] + (extent[2]-extent[0]) * pixel[0]/size[0],
        extent[1] + (extent[3]-extent[1]) * (size[1]-pixel[1])/size[1]
      ];
      console.log(JSON.stringify(extent));
      console.log(JSON.stringify(coordinate));  // as expected
      console.log(JSON.stringify(map.getCoordinateFromPixel(pixel)));  // hasn't been updated
    });
    

    .

    map.getView().on(['change:resolution','change:center'], function() {
      map.once('precompose', function() {
        console.log(JSON.stringify(map.getCoordinateFromPixel(pixel)));
      });
    });