diff --git a/src/ol/control/ScaleLine.js b/src/ol/control/ScaleLine.js index 76509844b9..f7d349f21a 100644 --- a/src/ol/control/ScaleLine.js +++ b/src/ol/control/ScaleLine.js @@ -201,20 +201,12 @@ class ScaleLine extends Control { ProjUnits.METERS; let pointResolution = getPointResolution(projection, viewState.resolution, center, pointResolutionUnits); - if (projection.getUnits() != ProjUnits.DEGREES && projection.getMetersPerUnit() - && pointResolutionUnits == ProjUnits.METERS) { - pointResolution *= projection.getMetersPerUnit(); - } let nominalCount = this.minWidth_ * pointResolution; let suffix = ''; if (units == Units.DEGREES) { const metersPerDegree = METERS_PER_UNIT[ProjUnits.DEGREES]; - if (projection.getUnits() == ProjUnits.DEGREES) { - nominalCount *= metersPerDegree; - } else { - pointResolution /= metersPerDegree; - } + nominalCount *= metersPerDegree; if (nominalCount < metersPerDegree / 60) { suffix = '\u2033'; // seconds pointResolution *= 3600; diff --git a/src/ol/proj.js b/src/ol/proj.js index f933af175f..89c0d74333 100644 --- a/src/ol/proj.js +++ b/src/ol/proj.js @@ -188,6 +188,12 @@ export function getPointResolution(projection, resolution, point, opt_units) { const getter = projection.getPointResolutionFunc(); if (getter) { pointResolution = getter(resolution, point); + if (opt_units && opt_units !== projection.getUnits()) { + const metersPerUnit = projection.getMetersPerUnit(); + if (metersPerUnit) { + pointResolution = pointResolution * metersPerUnit / METERS_PER_UNIT[opt_units]; + } + } } else { const units = projection.getUnits(); if (units == Units.DEGREES && !opt_units || opt_units == Units.DEGREES) { diff --git a/src/ol/proj/Projection.js b/src/ol/proj/Projection.js index ce4b2cb305..8c4f0d7ac7 100644 --- a/src/ol/proj/Projection.js +++ b/src/ol/proj/Projection.js @@ -19,7 +19,7 @@ import {METERS_PER_UNIT} from './Units.js'; * @property {function(number, import("../coordinate.js").Coordinate):number} [getPointResolution] * Function to determine resolution at a point. The function is called with a * `{number}` view resolution and an `{import("../coordinate.js").Coordinate}` as arguments, and returns - * the `{number}` resolution at the passed coordinate. If this is `undefined`, + * the `{number}` resolution in projection units at the passed coordinate. If this is `undefined`, * the default {@link module:ol/proj#getPointResolution} function will be used. */ diff --git a/test/spec/ol/control/scaleline.test.js b/test/spec/ol/control/scaleline.test.js index 81cb3495a4..2b79613bc8 100644 --- a/test/spec/ol/control/scaleline.test.js +++ b/test/spec/ol/control/scaleline.test.js @@ -1,8 +1,10 @@ import Map from '../../../../src/ol/Map.js'; import View from '../../../../src/ol/View.js'; import ScaleLine, {render} from '../../../../src/ol/control/ScaleLine.js'; -import {fromLonLat} from '../../../../src/ol/proj.js'; +import {fromLonLat, clearAllProjections, addCommon} from '../../../../src/ol/proj.js'; import Projection from '../../../../src/ol/proj/Projection.js'; +import proj4 from 'proj4'; +import {register} from '../../../../src/ol/proj/proj4.js'; describe('ol.control.ScaleLine', function() { let map; @@ -244,6 +246,25 @@ describe('ol.control.ScaleLine', function() { }); describe('projections affect the scaleline', function() { + + beforeEach(function() { + proj4.defs('Indiana-East', 'PROJCS["IN83-EF",GEOGCS["LL83",DATUM["NAD83",' + + 'SPHEROID["GRS1980",6378137.000,298.25722210]],PRIMEM["Greenwich",0],' + + 'UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],' + + 'PARAMETER["false_easting",328083.333],' + + 'PARAMETER["false_northing",820208.333],' + + 'PARAMETER["scale_factor",0.999966666667],' + + 'PARAMETER["central_meridian",-85.66666666666670],' + + 'PARAMETER["latitude_of_origin",37.50000000000000],' + + 'UNIT["Foot_US",0.30480060960122]]'); + register(proj4); + }); + + afterEach(function() { + clearAllProjections(); + addCommon(); + }); + it('is rendered differently for different projections', function() { const ctrl = new ScaleLine(); ctrl.setMap(map); @@ -253,15 +274,47 @@ describe('ol.control.ScaleLine', function() { projection: 'EPSG:3857' })); map.renderSync(); - const innerHtml3857 = ctrl.element.innerHTML; + expect(ctrl.element.innerText).to.be('2000 km'); map.setView(new View({ center: [7, 52], zoom: 2, projection: 'EPSG:4326' })); map.renderSync(); - const innerHtml4326 = ctrl.element.innerHTML; - expect(innerHtml4326).to.not.be(innerHtml3857); + expect(ctrl.element.innerText).to.be('5000 km'); + map.setView(new View({ + center: fromLonLat([-85.685, 39.891], 'Indiana-East'), + zoom: 7, + projection: 'Indiana-East' + })); + map.renderSync(); + expect(ctrl.element.innerText).to.be('100 km'); + }); + + it('shows the same scale for different projections at higher resolutions', function() { + const ctrl = new ScaleLine(); + ctrl.setMap(map); + map.setView(new View({ + center: fromLonLat([-85.685, 39.891]), + zoom: 7, + projection: 'EPSG:3857' + })); + map.renderSync(); + expect(ctrl.element.innerText).to.be('100 km'); + map.setView(new View({ + center: [-85.685, 39.891], + zoom: 7, + projection: 'EPSG:4326' + })); + map.renderSync(); + expect(ctrl.element.innerText).to.be('100 km'); + map.setView(new View({ + center: fromLonLat([-85.685, 39.891], 'Indiana-East'), + zoom: 7, + projection: 'Indiana-East' + })); + map.renderSync(); + expect(ctrl.element.innerText).to.be('100 km'); }); it('Projection\'s metersPerUnit affect scale for non-degree units', function() { @@ -344,7 +397,7 @@ describe('ol.control.ScaleLine', function() { const ctrl = new ScaleLine(); ctrl.setMap(map); map.setView(new View({ - center: fromLonLat([7, 0]), + center: [7, 0], zoom: 2, projection: 'EPSG:4326' })); @@ -362,7 +415,7 @@ describe('ol.control.ScaleLine', function() { }); ctrl.setMap(map); map.setView(new View({ - center: fromLonLat([7, 0]), + center: [7, 0], zoom: 2, projection: 'EPSG:4326' })); diff --git a/test/spec/ol/proj.test.js b/test/spec/ol/proj.test.js index f4a9f3583c..797a5a66d4 100644 --- a/test/spec/ol/proj.test.js +++ b/test/spec/ol/proj.test.js @@ -9,11 +9,12 @@ import { toLonLat, getTransform, getPointResolution, - getTransformFromProjections + getTransformFromProjections, + METERS_PER_UNIT } from '../../../src/ol/proj.js'; import {register} from '../../../src/ol/proj/proj4.js'; import {HALF_SIZE} from '../../../src/ol/proj/epsg3857.js'; -import {METERS_PER_UNIT} from '../../../src/ol/proj/epsg4326.js'; +import {METERS_PER_UNIT as metersPerDegree} from '../../../src/ol/proj/epsg4326.js'; import Projection from '../../../src/ol/proj/Projection.js'; @@ -268,7 +269,7 @@ describe('ol.proj', function() { expect(pointResolution).to.roughlyEqual(0.615661, 1e-5); }); it('returns the correct point resolution for EPSG:3857 with custom units', function() { - let pointResolution = getPointResolution('EPSG:3857', 1, [0, 0], 'degrees'); + let pointResolution = getPointResolution('EPSG:3857', METERS_PER_UNIT['degrees'], [0, 0], 'degrees'); expect(pointResolution).to.be(1); pointResolution = getPointResolution('EPSG:4326', 1, fromLonLat([0, 52]), 'degrees'); expect(pointResolution).to.be(1); @@ -600,7 +601,7 @@ describe('ol.proj', function() { it('returns value in meters', function() { const epsg4326 = getProjection('EPSG:4326'); - expect(epsg4326.getMetersPerUnit()).to.eql(METERS_PER_UNIT); + expect(epsg4326.getMetersPerUnit()).to.eql(metersPerDegree); }); it('works for proj4js projections without units', function() {