Skip to content

Commit

Permalink
Merge pull request openlayers#15891 from tschaub/sentinel-hub
Browse files Browse the repository at this point in the history
Sentinel Hub source
  • Loading branch information
tschaub authored Oct 16, 2024
2 parents 780e013 + 5256dc5 commit 9e574da
Show file tree
Hide file tree
Showing 15 changed files with 1,397 additions and 1 deletion.
1 change: 1 addition & 0 deletions config/tsconfig-strict.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@
"../src/ol/source/OGCVectorTile.js",
"../src/ol/source/OSM.js",
"../src/ol/source/Raster.js",
"../src/ol/source/SentinelHub.js",
"../src/ol/source/Source.js",
"../src/ol/source/StadiaMaps.js",
"../src/ol/source/static.js",
Expand Down
32 changes: 32 additions & 0 deletions examples/sentinel-hub-custom-script.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
dialog {
top: 13rem;
}

#auth-form {
display: flex;
flex-direction: column;
}

#auth-form>label {
margin-bottom: 1rem;
}

#auth-form>input[type=submit] {
margin-top: 1rem;
}

#evalscript-form {
display: flex;
flex-direction: column;
}

#evalscript-form>input[type=submit] {
margin-top: 1rem;
width: fit-content;
align-self: flex-end;
}

.cm-editor {
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 13px;
}
30 changes: 30 additions & 0 deletions examples/sentinel-hub-custom-script.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
layout: example.html
title: Sentinel Hub Custom Script
shortdesc: Updating the Evalscript used by the Sentinel Hub source.
docs: >
This example demonstrates how a custom script can be used to render tiles from Sentinel Hub.
Edit the `setup()` and `evaluatePixel()` functions above and click the update button to change the visualization.
See the Sentinel Hub [documentation on Evalscript](https://docs.sentinel-hub.com/api/latest/evalscript/) for more information.

See the [basic Sentinel Hub example](./sentinel-hub.html) for details on authentication.
tags: "Sentinel Hub, process, Evalscript"
---
<div id="map" class="map"></div>
<form id="evalscript-form">
<div id="evalscript"></div>
<input type="submit" value="update">
</form>
<dialog id="auth-dialog" open>
<form method="dialog" id="auth-form">
<label>Client id
<br>
<input type="text" name="id" autofocus>
</label>
<label>Client secret
<br>
<input type="password" name="secret">
</label>
<input type="submit" value="show map">
</form>
</dialog>
84 changes: 84 additions & 0 deletions examples/sentinel-hub-custom-script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import Map from '../src/ol/Map.js';
import SentinelHub from '../src/ol/source/SentinelHub.js';
import TileLayer from '../src/ol/layer/WebGLTile.js';
import View from '../src/ol/View.js';
import {EditorView, basicSetup} from 'codemirror';
import {javascript} from '@codemirror/lang-javascript';
import {useGeographic} from '../src/ol/proj.js';

useGeographic();

const source = new SentinelHub({
data: [
{
type: 'sentinel-2-l2a',
dataFilter: {
timeRange: {
from: '2024-05-15T00:00:00Z',
to: '2024-05-25T00:00:00Z',
},
},
},
],
});

const map = new Map({
layers: [new TileLayer({source})],
target: 'map',
view: new View({
center: [30.674, 29.935],
zoom: 10,
minZoom: 13,
maxZoom: 15,
}),
});

document.getElementById('auth-form').addEventListener('submit', (event) => {
const clientId = event.target.elements['id'].value;
const clientSecret = event.target.elements['secret'].value;
source.setAuth({clientId, clientSecret});
});

const script = `//VERSION=3
function setup() {
return {
input: ['B02', 'B03', 'B04', 'B08', 'B11'],
output: {bands: 3},
};
}
function evaluatePixel(sample) {
// Normalized Difference Moisture Index
const ndmi = (sample.B08 - sample.B11) / (sample.B08 + sample.B11);
if (ndmi <= 0) {
return [3 * sample.B04, 3 * sample.B03, 3 * sample.B02];
}
if (ndmi <= 0.2) {
return [0, 0.8, 0.9];
}
if (ndmi <= 0.4) {
return [0, 0.5, 0.9];
}
return [0, 0, 0.7];
}`;

const editor = new EditorView({
doc: script,
extensions: [basicSetup, javascript()],
parent: document.getElementById('evalscript'),
});

document
.getElementById('evalscript-form')
.addEventListener('submit', (event) => {
event.preventDefault();
source.setEvalscript(editor.state.doc.toString());
});

source.setEvalscript(script);

source.on('change', () => {
if (source.getState() === 'error') {
alert(source.getError());
}
});
16 changes: 16 additions & 0 deletions examples/sentinel-hub-date-picker.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
dialog {
top: 13rem;
}

#auth-form {
display: flex;
flex-direction: column;
}

#auth-form > label {
margin-bottom: 1rem;
}

#auth-form > input[type=submit] {
margin-top: 1rem;
}
29 changes: 29 additions & 0 deletions examples/sentinel-hub-date-picker.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
layout: example.html
title: Sentinel Hub Date Picker
shortdesc: Updating a Sentinel Hub source with new input data.
docs: >
This example renders tiles from Sentinel Hub based on imagery in a user-selected date range.
Changing the date picker above calls `source.setData()` with an updated time range in the data filter.

See the [basic Sentinel Hub example](./sentinel-hub.html) for details on authentication.
tags: "Sentinel Hub, process"
---
<div id="map" class="map"></div>
<dialog id="auth-dialog" open>
<form method="dialog" id="auth-form">
<label>Client id
<br>
<input type="text" name="id" autofocus>
</label>
<label>Client secret
<br>
<input type="password" name="secret">
</label>
<input type="submit" value="show map">
</form>
</dialog>
<label>
Show imagery from the week before&nbsp;
<input type="date" id="to-date" value="2024-06-01">
</label>
63 changes: 63 additions & 0 deletions examples/sentinel-hub-date-picker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Map from '../src/ol/Map.js';
import SentinelHub from '../src/ol/source/SentinelHub.js';
import TileLayer from '../src/ol/layer/WebGLTile.js';
import View from '../src/ol/View.js';
import {useGeographic} from '../src/ol/proj.js';

useGeographic();

const source = new SentinelHub({
evalscript: {
setup: () => ({
input: ['B02', 'B03', 'B04'],
output: {bands: 3},
}),
evaluatePixel: (sample) => [3 * sample.B04, 3 * sample.B03, 3 * sample.B02],
},
});

const map = new Map({
layers: [new TileLayer({source})],
target: 'map',
view: new View({
center: [-108.6, 43.185],
zoom: 12,
minZoom: 7,
maxZoom: 13,
}),
});

document.getElementById('auth-form').addEventListener('submit', (event) => {
const clientId = event.target.elements['id'].value;
const clientSecret = event.target.elements['secret'].value;
source.setAuth({clientId, clientSecret});
});

const picker = document.getElementById('to-date');

function updateInputData() {
const toDate = new Date(picker.value);
const fromDate = new Date(toDate.getTime());
fromDate.setDate(fromDate.getDate() - 7);

source.setData([
{
type: 'sentinel-2-l2a',
dataFilter: {
timeRange: {
from: fromDate.toISOString(),
to: toDate.toISOString(),
},
},
},
]);
}

picker.addEventListener('change', () => updateInputData());
updateInputData();

source.on('change', () => {
if (source.getState() === 'error') {
alert(source.getError());
}
});
16 changes: 16 additions & 0 deletions examples/sentinel-hub.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
dialog {
top: 13rem;
}

#auth-form {
display: flex;
flex-direction: column;
}

#auth-form > label {
margin-bottom: 1rem;
}

#auth-form > input[type=submit] {
margin-top: 1rem;
}
42 changes: 42 additions & 0 deletions examples/sentinel-hub.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
layout: example.html
title: Sentinel Hub
shortdesc: A tile source using the Sentinel Hub Processing API
docs: >
This example renders a tile layer with a source that uses the Sentinel Hub [Processing API](https://docs.sentinel-hub.com/api/latest/api/process/) to generate tiles.
The Processing API requires an access token. The form above can be used to provide an OAuth client id and secret.
The default client id and secret used in this example is severely rate limited. For the example to perform well,
you should register for your own client id and secret.
With this information, the source will fetch an access token. If an accesss token is fetched by other means, the `source.setAuth()`
method can be called the token directly. See the Sentinel Hub [authentication documentation](https://docs.sentinel-hub.com/api/latest/api/overview/authentication/) for details.

<p>
See these other examples for details on the following:
<ul>
<li>
<a href="./sentinel-hub-date-picker.html">Sentinel Hub Date Picker</a>
&mdash; calling <code>source.setData()</code> to update the time range for the input data.
</li>
<li>
<a href="./sentinel-hub-custom-script.html">Sentinel Hub Custom Script</a>
&mdash; calling <code>source.setEvalscript()</code> to update the Evalscript used in rendering tiles.
</li>
</ul>
</p>

tags: "Sentinel Hub, process"
---
<div id="map" class="map"></div>
<dialog id="auth-dialog" open>
<form method="dialog" id="auth-form">
<label>Client id
<br>
<input type="text" name="id" autofocus value="fa02a066-fc80-4cb4-af26-aae0af26cbf1">
</label>
<label>Client secret
<br>
<input type="password" name="secret" value="rate_limit_secret">
</label>
<input type="submit" value="show map">
</form>
</dialog>
55 changes: 55 additions & 0 deletions examples/sentinel-hub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Map from '../src/ol/Map.js';
import SentinelHub from '../src/ol/source/SentinelHub.js';
import TileLayer from '../src/ol/layer/WebGLTile.js';
import View from '../src/ol/View.js';
import {useGeographic} from '../src/ol/proj.js';

useGeographic();

const source = new SentinelHub({
data: [
{
type: 'sentinel-2-l2a',
dataFilter: {
timeRange: {
from: '2024-05-30T00:00:00Z',
to: '2024-06-01T00:00:00Z',
},
},
},
],
evalscript: {
setup: () => ({
input: ['B12', 'B08', 'B04'],
output: {bands: 3},
}),
evaluatePixel: (sample) => [
2.5 * sample.B12,
2 * sample.B08,
2 * sample.B04,
],
},
});

const map = new Map({
layers: [new TileLayer({source})],
target: 'map',
view: new View({
center: [-121.75, 46.85],
zoom: 10,
minZoom: 7,
maxZoom: 13,
}),
});

document.getElementById('auth-form').addEventListener('submit', (event) => {
const clientId = event.target.elements['id'].value;
const clientSecret = event.target.elements['secret'].value;
source.setAuth({clientId, clientSecret});
});

source.on('change', () => {
if (source.getState() === 'error') {
alert(source.getError());
}
});
Loading

0 comments on commit 9e574da

Please sign in to comment.