Choosing bands and applying contrast stretch
This example shows how to load multiple bands from a GeoZarr and use the layer.updateStyleVariables() method to update the rendering based on user selected bands and contrast stretch parameters.
import Map from 'ol/Map.js';
import {getView, withExtentCenter, withHigherResolutions} from 'ol/View.js';
import TileLayer from 'ol/layer/WebGLTile.js';
import GeoZarr from 'ol/source/GeoZarr.js';
import OSM from 'ol/source/OSM.js';
const channels = ['red', 'green', 'blue'];
for (const channel of channels) {
const selector = document.getElementById(channel);
selector.addEventListener('change', update);
const input = document.getElementById(`${channel}Max`);
input.addEventListener('input', update);
}
function getVariables() {
const variables = {};
for (const channel of channels) {
const selector = document.getElementById(channel);
variables[channel] = parseFloat(selector.value);
const inputId = `${channel}Max`;
const input = document.getElementById(inputId);
variables[inputId] = parseFloat(input.value);
}
return variables;
}
const source = new GeoZarr({
url: 'https://s3.explorer.eopf.copernicus.eu/esa-zarr-sentinel-explorer-fra/tests-output/sentinel-2-l2a-staging/S2B_MSIL2A_20251115T091139_N0511_R050_T35SLU_20251115T111807.zarr',
group: 'measurements/reflectance',
bands: ['b04', 'b03', 'b02', 'b11'],
});
const layer = new TileLayer({
style: {
variables: getVariables(),
gamma: 1.5,
color: [
'array',
['/', ['band', ['var', 'red']], ['var', 'redMax']],
['/', ['band', ['var', 'green']], ['var', 'greenMax']],
['/', ['band', ['var', 'blue']], ['var', 'blueMax']],
[
'case',
[
'==',
[
'+',
['band', ['var', 'red']],
['band', ['var', 'green']],
['band', ['var', 'blue']],
],
0,
],
0,
1,
],
],
},
source,
});
function update() {
layer.updateStyleVariables(getVariables());
}
const map = new Map({
target: 'map',
layers: [new TileLayer({source: new OSM()}), layer],
view: getView(source, withHigherResolutions(2), withExtentCenter()),
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Band Selection and Contrast Stretch</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">short-wave infrared</option>
</select>
<label>max
<input type="range" id="redMax" value="0.3" min="0.2" max="0.5" step="0.01">
</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">short-wave infrared</option>
</select>
<label>max
<input type="range" id="greenMax" value="0.3" min="0.2" max="0.5" step="0.01">
</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">short-wave infrared</option>
</select>
<label>max
<input type="range" id="blueMax" value="0.3" min="0.2" max="0.5" step="0.01">
</label>
</div>
<script type="module" src="main.js"></script>
</body>
</html>
{
"name": "geozarr-stretch",
"dependencies": {
"ol": "10.7.1-dev"
},
"devDependencies": {
"vite": "^3.2.3"
},
"scripts": {
"start": "vite",
"build": "vite build"
}
}