This example uses OpenLayers v10.9.0. The latest is v.
Edit

#### Projection and Scale

projection 14 scale 4

#####

View projection

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 {getPointResolution, get as getProjection, 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.9.0"
      },
      "devDependencies": {
        "vite": "^3.2.3"
      },
      "scripts": {
        "start": "vite",
        "build": "vite build"
      }
    }