diff --git a/examples/projection-and-scale.html b/examples/projection-and-scale.html new file mode 100644 index 0000000000..e98f25d8fd --- /dev/null +++ b/examples/projection-and-scale.html @@ -0,0 +1,18 @@ +--- +layout: example.html +title: Projection and Scale +shortdesc: Example of maintaining scale when changing projection. +docs: > + Example of maintaining scale when changing projection. + `getPointResolution()` is used to calculate the resolution for the + new projection which corresponds to that for the old projection. +tags: "projection, scale" +--- +
+
+ + +
diff --git a/examples/projection-and-scale.js b/examples/projection-and-scale.js new file mode 100644 index 0000000000..e32cb3bcaf --- /dev/null +++ b/examples/projection-and-scale.js @@ -0,0 +1,68 @@ +import Map from '../src/ol/Map.js'; +import OSM from '../src/ol/source/OSM.js'; +import TileLayer from '../src/ol/layer/Tile.js'; +import View from '../src/ol/View.js'; +import {ScaleLine, defaults as defaultControls} from '../src/ol/control.js'; +import { + getPointResolution, + get as getProjection, + transform, +} from '../src/ol/proj.js'; + +const viewProjSelect = document.getElementById('view-projection'); +const projection = getProjection(viewProjSelect.value); + +const scaleControl = new ScaleLine({ + units: 'metric', + bar: true, + steps: 4, + text: true, + minWidth: 140, +}); + +const map = new Map({ + controls: defaultControls().extend([scaleControl]), + layers: [ + new TileLayer({ + source: new OSM(), + }), + ], + target: 'map', + view: new View({ + center: transform([0, 52], 'EPSG:4326', projection), + zoom: 6, + projection: projection, + }), +}); + +function onChangeProjection() { + const currentView = map.getView(); + const currentProjection = currentView.getProjection(); + const newProjection = getProjection(viewProjSelect.value); + const currentResolution = currentView.getResolution(); + const currentCenter = currentView.getCenter(); + const currentRotation = currentView.getRotation(); + const newCenter = transform(currentCenter, currentProjection, newProjection); + const currentPointResolution = getPointResolution( + currentProjection, + 1, + currentCenter, + 'm' + ); + const newPointResolution = getPointResolution( + newProjection, + 1, + newCenter, + 'm' + ); + const newResolution = + (currentResolution * currentPointResolution) / newPointResolution; + const newView = new View({ + center: newCenter, + resolution: newResolution, + rotation: currentRotation, + projection: newProjection, + }); + map.setView(newView); +} +viewProjSelect.addEventListener('change', onChangeProjection); diff --git a/src/ol/control/ScaleLine.js b/src/ol/control/ScaleLine.js index 79fc6afccc..d97f29d33e 100644 --- a/src/ol/control/ScaleLine.js +++ b/src/ol/control/ScaleLine.js @@ -484,12 +484,12 @@ class ScaleLine extends Control { const resolution = getPointResolution( this.viewState_.projection, this.viewState_.resolution, - this.viewState_.center + this.viewState_.center, + ProjUnits.METERS ); const dpi = this.dpi_ || DEFAULT_DPI; - const mpu = this.viewState_.projection.getMetersPerUnit(); const inchesPerMeter = 1000 / 25.4; - return parseFloat(resolution.toString()) * mpu * inchesPerMeter * dpi; + return parseFloat(resolution.toString()) * inchesPerMeter * dpi; } /** diff --git a/test/browser/spec/ol/control/scaleline.test.js b/test/browser/spec/ol/control/scaleline.test.js index 2de14aadcc..076f83ff36 100644 --- a/test/browser/spec/ol/control/scaleline.test.js +++ b/test/browser/spec/ol/control/scaleline.test.js @@ -640,5 +640,49 @@ describe('ol.control.ScaleLine', function () { expect(text.slice(0, 4)).to.be('1 : '); expect(text.replace(/^1|\D/g, '')).to.eql(69885283); }); + it('it corresponds to the resolution in EPSG:4326', function () { + const ctrl = new ScaleLine({ + bar: true, + text: true, + }); + ctrl.setMap(map); + map.setView( + new View({ + center: [0, 0], + zoom: 2, + multiWorld: true, + projection: 'EPSG:4326', + }) + ); + map.renderSync(); + const element = document.querySelector('.ol-scale-text', map.getTarget()); + expect(element).to.not.be(null); + expect(element).to.be.a(HTMLDivElement); + const text = element.innerText; + expect(text.slice(0, 4)).to.be('1 : '); + expect(text.replace(/^1|\D/g, '')).to.eql(139614359); + }); + it('it changes with latitude in EPSG:4326', function () { + const ctrl = new ScaleLine({ + bar: true, + text: true, + }); + ctrl.setMap(map); + map.setView( + new View({ + center: [0, 60], + zoom: 2, + multiWorld: true, + projection: 'EPSG:4326', + }) + ); + map.renderSync(); + const element = document.querySelector('.ol-scale-text', map.getTarget()); + expect(element).to.not.be(null); + expect(element).to.be.a(HTMLDivElement); + const text = element.innerText; + expect(text.slice(0, 4)).to.be('1 : '); + expect(text.replace(/^1|\D/g, '')).to.eql(104710728); + }); }); });