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

#### Populated Places

vector 86 interpolate 1

#####

Scaling and coloring points according to population.

The populated places dataset has a `pop_max` field that is used in rendering the style for each place. The `interpolate` operator is used to scale the `circle-radius`, rendering a point with a radius of 3 for places with a population under 500 thousand, growing to a point with a radius of 10 for places with a population of 10 million or more. The same `interpolate` operator is used to generate a color ramp for places based on the same `pop_max` field.

##### main.js

    import Map from 'ol/Map.js';
    import View from 'ol/View.js';
    import GeoJSON from 'ol/format/GeoJSON.js';
    import Link from 'ol/interaction/Link.js';
    import TileLayer from 'ol/layer/Tile.js';
    import VectorLayer from 'ol/layer/Vector.js';
    import VectorSource from 'ol/source/Vector.js';
    import XYZ from 'ol/source/XYZ.js';

    const populatedPlaces = new VectorLayer({
      source: new VectorSource({
        url: 'https://openlayers.org/data/vector/populated-places.json',
        format: new GeoJSON(),
      }),
      style: {
        'circle-stroke-color': 'hsl(0 100% 100% / 0.9)',
        'circle-stroke-width': 0.75,
        'circle-radius': [
          'interpolate',
          ['linear'],
          ['get', 'pop_max'],
          500_000,
          3,
          10_000_000,
          10,
        ],
        'circle-fill-color': [
          'interpolate',
          ['linear'],
          ['get', 'pop_max'],
          1_000_000,
          'hsl(210 100% 40% / 0.9)',
          10_000_000,
          'hsl(0 80% 60% / 0.9)',
        ],
      },
    });

    const key = 'Get your own API key at https://www.maptiler.com/cloud/';

    const map = new Map({
      layers: [
        new TileLayer({
          source: new XYZ({
            attributions:
              '<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> ' +
              '<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>',
            url:
              'https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=' + key,
            tileSize: 512,
            maxZoom: 20,
          }),
        }),
        populatedPlaces,
      ],
      target: 'map',
      view: new View({
        center: [0, 0],
        zoom: 1,
      }),
    });

    map.addInteraction(new Link());

    const info = document.getElementById('info');

    let currentFeature = null;
    function displayFeatureInfo(pixel, width) {
      const feature = map.getFeaturesAtPixel(pixel)[0];
      if (feature) {
        const featurePixel = map.getPixelFromCoordinate(
          feature.getGeometry().getCoordinates(),
        );
        if (featurePixel[0] > width) {
          featurePixel[0] = featurePixel[0] % width;
        } else if (featurePixel[1] < width) {
          featurePixel[0] = width + (featurePixel[0] % width);
        }
        info.style.top = featurePixel[1] + 'px';
        if (featurePixel[0] < width / 2) {
          info.style.left = featurePixel[0] + 'px';
          info.style.right = 'auto';
        } else {
          info.style.right = width - featurePixel[0] + 'px';
          info.style.left = 'auto';
        }
        if (feature !== currentFeature) {
          info.style.visibility = 'visible';
          info.innerHTML =
            feature.get('name') + '<br>' + feature.get('pop_max').toLocaleString();
        }
      } else if (currentFeature) {
        info.style.visibility = 'hidden';
      }
      currentFeature = feature;
    }

    map.on('pointermove', function (evt) {
      if (evt.dragging) {
        info.style.visibility = 'hidden';
        currentFeature = undefined;
        return;
      }
      displayFeatureInfo(evt.pixel, evt.frameState.size[0]);
    });

    map.on('click', function (evt) {
      displayFeatureInfo(evt.pixel, evt.frameState.size[0]);
    });

    map.getTargetElement().addEventListener('pointerleave', function () {
      currentFeature = undefined;
      info.style.visibility = 'hidden';
    });

##### index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Populated Places</title>
        <link rel="stylesheet" href="node_modules/ol/ol.css">
        <style>
          .map {
            width: 100%;
            height: 400px;
          }
          #map {
            position: relative;
          }

          #info {
            position: absolute;
            display: inline-block;
            height: auto;
            width: auto;
            z-index: 100;
            background-color: #333;
            color: #fff;
            text-align: center;
            border-radius: 4px;
            padding: 5px;
            left: 50%;
            transform: translateX(3%);
            visibility: hidden;
            pointer-events: none;
          }
        </style>
      </head>
      <body>
        <div id="map" class="map">
          <div id="info">&nbsp;</div>
        </div>

        <script type="module" src="main.js"></script>
      </body>
    </html>

##### package.json

    {
      "name": "populated-places",
      "dependencies": {
        "ol": "10.9.0"
      },
      "devDependencies": {
        "vite": "^3.2.3"
      },
      "scripts": {
        "start": "vite",
        "build": "vite build"
      }
    }