OpenLayers – How to Get Map Units to Find Current Scale in OpenLayers?

openlayersproj

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?)

Best Answer

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;
};
Related Question