4

I need my OpenLayers application to be able to determine the current scale. This is not for display (there is already the scale line for that). This is because I have a scale-dependent style function, to display styles differently at different scales. I need to be able to do it according to scales, not resolutions, because the styles and their respective scales, are configured by the user, and the user enters scale values similar to how they would in a GIS for layer display constraints. (Ie, although scales are not great for on-screen, they are what users are used to using to constrain styles/layers to specific resolutions).

This is all working well in my app, changing styles as I zoom in and out. Except that my calculation of the current scale is incorrect. For testing purposes, I've simply calculating the scale (incorrectly) as:

resolution * DPI

I think that the correct way to calculate the scale would be:

resolution * meters-per-map-unit * inches-per-metre * DPI

The only part of this I cannot figure out is the metres-per-map-unit. there is the ol.proj.METERS_PER_UNIT lookup, but I can't use it because I don't know what the current unit is. My users may have swapped in any map of any projection in the application, so I need to be able to determine the current unit dynamically.

How can I get the current map unit from OpenLayers?

Or can I get it from proj4.js for the current projection? (and if so, is that the same thing?)

7

The units are within the projection of the view. From a map object, you can get it using:

var units = map.getView().getProjection().getUnits();

See also the API documentation of the ol.proj.Projection#getUnits method.

Here's also an example method to get the scale from a given resolution:

var INCHES_PER_UNIT = {
  'm': 39.37,
  'dd': 4374754
};
var DOTS_PER_INCH = 72;

/**
 * @param {number} resolution Resolution.
 * @param {string} units Units
 * @param {boolean=} opt_round Whether to round the scale or not.
 * @return {number} Scale
 */
var getScaleFromResolution = function(resolution, units, opt_round) {
  var scale = INCHES_PER_UNIT[units] * DOTS_PER_INCH * resolution;
  if (opt_round) {
    scale = Math.round(scale);
  }
  return scale;
};
5

Inspired by @Alexandre's answer, I came up with something a little different that suits my use-case better. In this case, I know that I have a map with a view and projection, and from that I can derive everything else required to calculate the scale except for the DPI. In my app, DPI cannot be hard-coded because the app runs on mobile devices with screens of variable resolutions. So DPI is the only parameter I pass in to my function.

This could all be done on one line, but I added the 3 var lines in order to make it more human readable.

This is what I've ended up using:

function mapScale (dpi) {
    var unit = map.getView().getProjection().getUnits();
    var resolution = map.getView().getResolution();
    var inchesPerMetre = 39.37;

    return resolution * ol.proj.METERS_PER_UNIT[unit] * inchesPerMetre * dpi;
}

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.