Edit

Multiple COG sources

cog13 webgl17 projection13 reprojection7

Displaying two Sentinel 2 COGs with different projections

Two Sentinel 2 COGs each with sources for visible red, green and blue bands, and a near-infrared band. The adjacent regions are at the edge of their respective UTM zones so at least one COG must be reprojected to be displayed on the same map.

main.js
import GeoTIFF from 'ol/source/GeoTIFF.js';
import Map from 'ol/Map.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import proj4 from 'proj4';
import {createEmpty, extend, getCenter} from 'ol/extent.js';
import {register} from 'ol/proj/proj4.js';
import {transformExtent} from 'ol/proj.js';

proj4.defs('EPSG:32631', '+proj=utm +zone=31 +datum=WGS84 +units=m +no_defs');
proj4.defs('EPSG:32632', '+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs');
register(proj4);

const channels = ['red', 'green', 'blue'];
for (const channel of channels) {
  const selector = document.getElementById(channel);
  selector.addEventListener('change', update);
}

function getVariables() {
  const variables = {};
  for (const channel of channels) {
    const selector = document.getElementById(channel);
    variables[channel] = parseInt(selector.value, 10);
  }
  return variables;
}

const sourceNames = ['B04', 'B03', 'B02', 'B08'];
const sources = [
  new GeoTIFF({
    sources: sourceNames.map(function (name) {
      return {
        url: `https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/31/T/GJ/2022/7/S2A_31TGJ_20220703_0_L2A/${name}.tif`,
        max: 3000,
      };
    }),
  }),
  new GeoTIFF({
    sources: sourceNames.map(function (name) {
      return {
        url: `https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/32/T/LP/2022/7/S2A_32TLP_20220703_0_L2A/${name}.tif`,
        max: 3000,
      };
    }),
  }),
];

const layer = new TileLayer({
  sources: sources,
  style: {
    variables: getVariables(),
    color: [
      'array',
      ['band', ['var', 'red']],
      ['band', ['var', 'green']],
      ['band', ['var', 'blue']],
      ['band', 5],
    ],
  },
});

function update() {
  layer.updateStyleVariables(getVariables());
}

const map = new Map({
  target: 'map',
  layers: [layer],
  view: Promise.all(
    sources.map(function (source) {
      return source.getView();
    }),
  ).then(function (options) {
    const projection = 'EPSG:3857';
    const extent = createEmpty();
    options.forEach(function (options) {
      extend(
        extent,
        transformExtent(options.extent, options.projection, projection),
      );
    });
    return {
      projection: projection,
      center: getCenter(extent),
      zoom: 0,
      extent: extent,
    };
  }),
});
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Multiple COG sources</title>
    <link rel="stylesheet" href="node_modules/ol/ol.css">
    <style>
      .map {
        width: 100%;
        height: 400px;
      }
      .controls {
        display: grid;
        grid-template-columns: auto auto 1fr;
        align-items: baseline;
        gap: 0 1em;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <div class="controls">
      <label for="red">Red channel</label>
      <select id="red">
        <option value="1" selected>visible red</option>
        <option value="2">visible green</option>
        <option value="3">visible blue</option>
        <option value="4">near infrared</option>
      </select>
      <label></label>

      <label for="green">Green channel</label>
      <select id="green">
        <option value="1">visible red</option>
        <option value="2" selected>visible green</option>
        <option value="3">visible blue</option>
        <option value="4">near infrared</option>
      </select>
      <label></label>

      <label for="blue">Blue channel</label>
      <select id="blue">
        <option value="1">visible red</option>
        <option value="2">visible green</option>
        <option value="3" selected>visible blue</option>
        <option value="4">near infrared</option>
      </select>
      <label></label>
    </div>

    <script type="module" src="main.js"></script>
  </body>
</html>
package.json
{
  "name": "multiple-cogs",
  "dependencies": {
    "ol": "10.0.1-dev",
    "proj4": "2.11.0"
  },
  "devDependencies": {
    "vite": "^3.2.3"
  },
  "scripts": {
    "start": "vite",
    "build": "vite build"
  }
}