Edit

Projection and Scale

projection14 scale4

Example of maintaining scale when changing projection.

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.

main.js
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import ScaleLine from 'ol/control/ScaleLine.js';
import {defaults as defaultControls} from 'ol/control/defaults.js';
import TileLayer from 'ol/layer/Tile.js';
import {
  get as getProjection,
  getPointResolution,
  transform,
} from 'ol/proj.js';
import OSM from 'ol/source/OSM.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 currentMPU = currentProjection.getMetersPerUnit();
  const newMPU = newProjection.getMetersPerUnit();
  const currentPointResolution =
    getPointResolution(currentProjection, 1 / currentMPU, currentCenter, 'm') *
    currentMPU;
  const newPointResolution =
    getPointResolution(newProjection, 1 / newMPU, newCenter, 'm') * newMPU;
  const newResolution =
    (currentResolution * currentPointResolution) / newPointResolution;
  const newView = new View({
    center: newCenter,
    resolution: newResolution,
    rotation: currentRotation,
    projection: newProjection,
  });
  map.setView(newView);
}
viewProjSelect.addEventListener('change', onChangeProjection);
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Projection and Scale</title>
    <link rel="stylesheet" href="node_modules/ol/ol.css">
    <style>
      .map {
        width: 100%;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <div>
      <label for="view-projection">View projection</label>
      <select id="view-projection">
        <option value="EPSG:3857">Spherical Mercator (EPSG:3857)</option>
        <option value="EPSG:4326" selected>WGS 84 (EPSG:4326)</option>
      </select>
    </div>

    <script type="module" src="main.js"></script>
  </body>
</html>
package.json
{
  "name": "projection-and-scale",
  "dependencies": {
    "ol": "10.4.0"
  },
  "devDependencies": {
    "vite": "^3.2.3"
  },
  "scripts": {
    "start": "vite",
    "build": "vite build"
  }
}