Choosing bands and applying contrast stretch
This example uses the layer.updateStyleVariables()
method to update the rendering of a GeoTIFF based on user selected bands and contrast stretch parameters.
import 'ol/ol.css';
import GeoTIFF from 'ol/source/GeoTIFF';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/WebGLTile';
import View from 'ol/View';
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] = parseInt(selector.value, 10);
const inputId = `${channel}Max`;
const input = document.getElementById(inputId);
variables[inputId] = parseInt(input.value, 10);
}
return variables;
}
const layer = new TileLayer({
style: {
variables: getVariables(),
color: [
'array',
['/', ['band', ['var', 'red']], ['var', 'redMax']],
['/', ['band', ['var', 'green']], ['var', 'greenMax']],
['/', ['band', ['var', 'blue']], ['var', 'blueMax']],
1,
],
},
source: new GeoTIFF({
normalize: false,
sources: [
{
url: 'https://s2downloads.eox.at/demo/EOxCloudless/2020/rgbnir/s2cloudless2020-16bits_sinlge-file_z0-4.tif',
},
],
}),
});
function update() {
layer.updateStyleVariables(getVariables());
}
const map = new Map({
target: 'map',
layers: [layer],
view: new View({
projection: 'EPSG:4326',
center: [0, 0],
zoom: 2,
maxZoom: 6,
}),
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Band Contrast Stretch</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<!-- The lines below are only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,TextDecoder"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.3/minified.js"></script>
<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>max
<input type="range" id="redMax" value="3000" min="2000" max="5000">
</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>max
<input type="range" id="greenMax" value="3000" min="2000" max="5000">
</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>max
<input type="range" id="blueMax" value="3000" min="2000" max="5000">
</label>
</div>
<script src="main.js"></script>
</body>
</html>
{
"name": "cog-stretch",
"dependencies": {
"ol": "6.12.0"
},
"devDependencies": {
"parcel": "^2.0.0"
},
"scripts": {
"start": "parcel index.html",
"build": "parcel build --public-url . index.html"
}
}