My starting point for this question is the ability to print a map with a given format&resolution, very similar to the "Export to PDF" example at OpenLayers webpages: https://openlayers.org/en/latest/examples/export-pdf.html

I am not using the jsPDF library, but using similar approach of drawing to a printCanvas.

My challenge comes from when there is a measurement overlay in the map that should be printed. This is a screenshot from my map:

Map with measurement overlay

If I print my map "as is", meaning not changing format or resolution making sure the map size stays the same, everything is fine. I have created a canvas "renderer" of the overlay element, and this works decently.

However, when DPI/resolution or Format is modified, the size of the map changes. And hence I need to reposition my overlay.

My initial thought was that this shouldn't be too difficult, in my mind I wanted to implement it like this:

  1. Get the current position of the overlay in pixel coordinates.
  2. Calculate the ratio for width and height by taking new map size w/h and dividing it on old map size w/h
  3. "Translate" the old pixel coordinates to new pixel coordinates by multiplying them with the ratio
  4. Calculate the new actual coordinates by using the Map -> getCoordinateFromPixel() method
  5. Update the overlay position by using Overlay -> setPosition()

A simple small example on paper:

Old map size: 100w 100h
Old overlay position in pixels coords: 50,50
--- Increase map size by the double ---
New map size: 200w 200h
widthRatio = 2
heightRatio = 2
New overlay position in pixel coords: 100,100

However when I use my translated pixel coordinates, and update the position of my overlay, it does not render where it should:

Position of overlay is wrong

In the example of the pictures I've gone from a map size of 1920w 956h to 2012w 1002h, so just a slight expansion of the map size.

I do believe that I know the reason for this, but I don't know how to handle it. I assume the problem is related to the fact that when map changes size - the viewport doesn't, so the getCoordinateFromPixel() is returning "wrong" coordinates for the new map size.

I verified this "assumption" by getting the line/geometry of the measure, and printing the geometry.getLastCoordinate() in pixel coordinates both before and after the map.setSize() method:

var size = [1920, 956];
var coord = getPixelFromCoordinate(geometry.getLastCoordinate())
coord with original map size 1920x956 = [1169,439]

//increase map size and set new resolution
var printSize = [2012, 1002];
var scaling = Math.min(width / size[0], height / size[1]);
map.getView().setResolution(viewResolution / scaling);

//print pixel coordinates again
coord = getPixelFromCoordinate(geometry.getLastCoordinate())
coord with new map size 2012x1002 = [1169,439]

So despite the map size was increased, the pixel position is still the same for the feature - which I believe comes from the fact that the viewport did not change.

The API documentation for getPixelFromCoordinate() states "A pixel position in the map viewport." - so this is correct behavior I assume, but what can I do here to "translate" the position correctly according to the new map size?

If there is a simple apparent solution here I will apologize upfront for spending your time to read this, but I have made multiple attempts and not yet been able to find a solution to this.

Kind Regards,

Eivind Rønnevik

  • An easier way to print the measure would be to include it as part of the style instead of a displaying it in the overlay codesandbox.io/s/measure-zmqyy – Mike Apr 7 '20 at 15:46
  • @Mike, thank you for that idea - I didn't think of it! Definitively a way to go for achieving this! – Eivind Rønnevik Apr 8 '20 at 16:14

Sorry all, this seems to be caused by me not waiting for the rendercomplete event of the map before setting position of the overlay with the translated pixel coordinates.

  • So did you solve the issue then? Could you write your solution here please? As in, which line / s of code you added to get it to wait. – Dane Rossenrode Apr 9 '20 at 12:31
  • Hi Dane, after changing map size - you need to get the new position of the overlay after the map.rendercomplete event has been fired. So either inside of this method or using some other mechanism to check when rendercomplete is fired. See the API documentation for more details: openlayers.org/en/latest/apidoc/… – Eivind Rønnevik Apr 10 '20 at 21:25

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.