Skip to content

Commit

Permalink
Updated examples and fixed GEE tests, release 1.0.0-beta.1
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr committed May 12, 2020
1 parent 959ae43 commit d876586
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 80 deletions.
54 changes: 9 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The version of this client is **1.0.0-beta.1** and supports **openEO API version

## Usage

This library can run in node.js or any recent browser (excluding Internet Explorer).
This library can run in node.js or any recent browser (Internet Explorer not tested).

### Browser environment

Expand All @@ -25,9 +25,16 @@ To install it in a NodeJS environment run: `npm install @openeo/js-client`

Afterwards, you can import the package: `const { OpenEO } = require('@openeo/js-client');`

### Examples

* [Basic Discovery (promises)](examples/discovery.html)
* [Run sync. job (async/await)](examples/workflow.html)

More information can be found in the [**JS client documentation**](https://open-eo.github.io/openeo-js-client/1.0.0-beta.1/).

### Advanced options

Generate a minified build: `npm run build`
Generate a build: `npm run build` (generates `openeo.js` and `openeo.min.js`)

Generate the documentation to the `docs/` folder: `npm run docs`

Expand All @@ -40,49 +47,6 @@ Run tests:
* `npm run test_node` (node tests)
* `npm run test_gee` (full test suite using the Google Earth Engine back-end as server)

### Running a job

```js
// Show the client version
console.log("Client Version: " + OpenEO.clientVersion());

try {
// Connect to the back-end
var con = await OpenEO.connect("https://earthengine.openeo.org", "basic", {username: "group1", password: "test123"});

// Show implemented API version of the back-end
var capabilities = con.capabilities();
console.log("Server API version: " + capabilities.apiVersion());

// List collection names
var collections = await con.listCollections();
console.log("Collections: " + collections.collections.map(c => c.name));

// List process ids
var processes = await con.listProcesses();
console.log("Processes: " + processes.processes.map(p => p.name));

// List supported file types
var fileTypes = await con.listFileTypes();
console.log("Files types: " + Object.keys(fileTypes.formats));

// Check whether synchronous previews are supported
var syncSupport = capabilities.hasFeature("computeResult");
console.log("Synchronous previews: " + (syncSupport ? "supported" : "NOT supported"));

// Request a preview synchronously for a process graph
if (syncSupport) {
// Replace ... with your JSON process graph
var preview = await con.computeResult(..., "png");
// This returns a Blob object containing a binary PNG file you could further process or show.
}
} catch(e) {
console.log(e);
}
```

More information can be found in the [**JS client documentation**](https://open-eo.github.io/openeo-js-client/1.0.0-beta.1/).

## Roadmap

* There's no functionality to build process graphs. An easy-to-use process graph builder is envisioned to be implemented. [#19](https://github.com/Open-EO/openeo-js-client/issues/19)
Expand Down
61 changes: 32 additions & 29 deletions examples/discovery.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>openEO JS client - Discovery example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/axios@0.19/dist/axios.min.js"></script>
<script src="../openeo.js"></script>
<script type="text/javascript">
var url = "https://earthengine.openeo.org"; // Insert the openEO server URL here
var connection = null;

window.onload = function () {
document.getElementById('url').innerText = url;
document.getElementById('clientVersion').innerText = OpenEO.clientVersion();
<head>
<title>openEO JS client - Discovery example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/axios@0.19/dist/axios.min.js"></script>
<script src="../openeo.js"></script>
<script type="text/javascript">
var url = "https://earthengine.openeo.org"; // Insert the openEO server URL here
var connection = null;

OpenEO.connect(url)
window.onload = function () {
document.getElementById('url').innerText = url;
document.getElementById('clientVersion').innerText = OpenEO.clientVersion();

OpenEO.connect(url)
.then(c => {
connection = c;
return connection.capabilities();
Expand All @@ -32,20 +33,22 @@
return;
})
.catch(err => alert(err.message));;
};
</script>
</head>
<body>
<h1>Server information</h1>
<p>URL: <span id="url"></span></p>
<h2>Versions</h2>
<ul>
<li>Client Version: <span id="clientVersion">Loading...</span></li>
<li>Server Version: <span id="serverVersion">Loading...</span></li>
</ul>
<h2>EO Data Discovery</h2>
<p>Number of supported collections: <span id="collectionCount">Loading...</span></p>
<h2>Process Discovery</h2>
<p>Number of supported processes: <span id="processCount">Loading...</span></p>
</body>
};
</script>
</head>

<body>
<h1>Server information</h1>
<p>URL: <span id="url"></span></p>
<h2>Versions</h2>
<ul>
<li>Client Version: <span id="clientVersion">Loading...</span></li>
<li>Server Version: <span id="serverVersion">Loading...</span></li>
</ul>
<h2>EO Data Discovery</h2>
<p>Number of supported collections: <span id="collectionCount">Loading...</span></p>
<h2>Process Discovery</h2>
<p>Number of supported processes: <span id="processCount">Loading...</span></p>
</body>

</html>
67 changes: 67 additions & 0 deletions examples/workflow.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>

<head>
<title>openEO JS client - Workflow example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/axios@0.19/dist/axios.min.js"></script>
<script src="../openeo.js"></script>
<script type="text/javascript">
async function run() {
// Show the client version
log("Client Version: " + OpenEO.clientVersion());

try {
// Connect to the back-end
var con = await OpenEO.connect("https://earthengine.openeo.org");

// Show implemented API version of the back-end
var capabilities = con.capabilities();
log("Server API version: " + capabilities.apiVersion());

// List collection names
var collections = await con.listCollections();
log("Collections: " + collections.collections.map(c => c.id).join(', '));

// List process ids
var processes = await con.listProcesses();
log("Processes: " + processes.processes.map(p => p.id).join(', '));

// List supported file types
var types = await con.listFileTypes();
log("Input file formats: " + Object.keys(types.getInputTypes()).join(', '));
log("Output file formats: " + Object.keys(types.getOutputTypes()).join(', '));

// Authenticate at back-end using HTTP Basic
await con.authenticateBasic("group1", "test123");

// Request user info
var user = await con.describeAccount();
log("User: " + user.user_id);

// Check whether synchronous previews are supported
var syncSupport = capabilities.hasFeature("computeResult");
log("Synchronous previews: " + (syncSupport ? "supported" : "NOT supported"));

// Request a preview synchronously for a process graph
var pg = {}; // Specify your user-defined process here...
if (syncSupport) {
// Replace ... with your JSON process graph
log("Running process...");
var preview = await con.computeResult(pg);
// This returns a Blob object containing a binary PNG file you could further process or show.
}
} catch (e) {
log("Error: " + e.message);
}
}
function log(text) {
document.getElementById('console').innerHTML += "<p>" + text + "</p>";
}
</script>
</head>

<body onload="run()"><code id="console"></code></body>

</html>
15 changes: 9 additions & 6 deletions tests/earthengine.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('With earth-engine-driver', () => {

const TESTCOLLECTION = {"stac_version":"0.9.0","id":"AAFC/ACI","title":"Canada AAFC Annual Crop Inventory","description":"Starting in 2009, the Earth Observation Team of the Science and Technology\nBranch (STB) at Agriculture and Agri-Food Canada (AAFC) began the process\nof generating annual crop type digital maps. Focusing on the Prairie\nProvinces in 2009 and 2010, a Decision Tree (DT) based methodology was\napplied using optical (Landsat-5, AWiFS, DMC) and radar (Radarsat-2) based\nsatellite images. Beginning with the 2011 growing season, this activity has\nbeen extended to other provinces in support of a national crop inventory.\nTo date this approach can consistently deliver a crop inventory that meets\nthe overall target accuracy of at least 85% at a final spatial resolution of\n30m (56m in 2009 and 2010).\n","version":"","license":"proprietary","links":[{"href":TESTBACKENDDIRECT+"/collections/AAFC/ACI","rel":"self"},{"href":TESTBACKENDDIRECT+"/collections","rel":"parent"},{"href":TESTBACKENDDIRECT+"/collections","rel":"root"},{"href":"https://mw1.google.com/ges/dd/images/AAFC_ACI_sample.png","rel":"preview"},{"href":"http://www.agr.gc.ca/atlas/data_donnees/agr/annualCropInventory/tif","rel":"source"}],"keywords":["aafc","canada","crop","landcover"],"providers":[{"roles":["producer","licensor"],"name":"Agriculture and Agri-Food Canada","url":"https://open.canada.ca/data/en/dataset/ba2645d5-4458-414d-b196-6303ac06c1c9"},{"roles":["host"],"name":"Google Earth Engine","url":"https://developers.google.com/earth-engine/datasets/catalog/AAFC_ACI"}],"extent":{"spatial":{"bbox":[[-135.17,36.83,-51.24,62.25]]},"temporal":{"interval":[["2009-01-01T00:00:00Z",null]]}},"summaries":{"gee:type":["image_collection"],"gee:schema":[{"landcover_class_names":{"description":"Array of cropland landcover classification names.","type":"STRING_LIST"},"landcover_class_palette":{"description":"Array of hex code color strings used for the classification palette.","type":"STRING_LIST"},"landcover_class_values":{"description":"Value of the land cover classification.","type":"INT_LIST"}}],"eo:gsd":[30],"eo:bands":[{"name":"landcover","description":"Main crop-specific land cover classification.","gee:classes":[{"value":10,"description":"Cloud","color":"000000"},{"value":20,"description":"Water","color":"3333ff"},{"value":30,"description":"Exposed Land and Barren","color":"996666"},{"value":34,"description":"Urban and Developed","color":"cc6699"},{"value":35,"description":"Greenhouses","color":"e1e1e1"},{"value":50,"description":"Shrubland","color":"ffff00"},{"value":80,"description":"Wetland","color":"993399"},{"value":110,"description":"Grassland","color":"cccc00"},{"value":120,"description":"Agriculture (undifferentiated)","color":"cc6600"},{"value":122,"description":"Pasture and Forages","color":"ffcc33"},{"value":130,"description":"Too Wet to be Seeded","color":"7899f6"},{"value":131,"description":"Fallow","color":"ff9900"},{"value":132,"description":"Cereals","color":"660000"},{"value":133,"description":"Barley","color":"dae31d"},{"value":134,"description":"Other Grains","color":"d6cc00"},{"value":135,"description":"Millet","color":"d2db25"},{"value":136,"description":"Oats","color":"d1d52b"},{"value":137,"description":"Rye","color":"cace32"},{"value":138,"description":"Spelt","color":"c3c63a"},{"value":139,"description":"Triticale","color":"b9bc44"},{"value":140,"description":"Wheat","color":"a7b34d"},{"value":141,"description":"Switchgrass","color":"b9c64e"},{"value":142,"description":"Sorghum","color":"999900"},{"value":145,"description":"Winter Wheat","color":"92a55b"},{"value":146,"description":"Spring Wheat","color":"809769"},{"value":147,"description":"Corn","color":"ffff99"},{"value":148,"description":"Tobacco","color":"98887c"},{"value":149,"description":"Ginseng","color":"799b93"},{"value":150,"description":"Oilseeds","color":"5ea263"},{"value":151,"description":"Borage","color":"52ae77"},{"value":152,"description":"Camelina","color":"41bf7a"},{"value":153,"description":"Canola and Rapeseed","color":"d6ff70"},{"value":154,"description":"Flaxseed","color":"8c8cff"},{"value":155,"description":"Mustard","color":"d6cc00"},{"value":156,"description":"Safflower","color":"ff7f00"},{"value":157,"description":"Sunflower","color":"315491"},{"value":158,"description":"Soybeans","color":"cc9933"},{"value":160,"description":"Pulses","color":"896e43"},{"value":162,"description":"Peas","color":"8f6c3d"},{"value":167,"description":"Beans","color":"82654a"},{"value":174,"description":"Lentils","color":"b85900"},{"value":175,"description":"Vegetables","color":"b74b15"},{"value":176,"description":"Tomatoes","color":"ff8a8a"},{"value":177,"description":"Potatoes","color":"ffcccc"},{"value":178,"description":"Sugarbeets","color":"6f55ca"},{"value":179,"description":"Other Vegetables","color":"ffccff"},{"value":180,"description":"Fruits","color":"dc5424"},{"value":181,"description":"Berries","color":"d05a30"},{"value":182,"description":"Blueberry","color":"d20000"},{"value":183,"description":"Cranberry","color":"cc0000"},{"value":185,"description":"Other Berry","color":"dc3200"},{"value":188,"description":"Orchards","color":"ff6666"},{"value":189,"description":"Other Fruits","color":"c5453b"},{"value":190,"description":"Vineyards","color":"7442bd"},{"value":191,"description":"Hops","color":"ffcccc"},{"value":192,"description":"Sod","color":"b5fb05"},{"value":193,"description":"Herbs","color":"ccff05"},{"value":194,"description":"Nursery","color":"07f98c"},{"value":195,"description":"Buckwheat","color":"00ffcc"},{"value":196,"description":"Canaryseed","color":"cc33cc"},{"value":197,"description":"Hemp","color":"8e7672"},{"value":198,"description":"Vetch","color":"b1954f"},{"value":199,"description":"Other Crops","color":"749a66"},{"value":200,"description":"Forest (undifferentiated)","color":"009900"},{"value":210,"description":"Coniferous","color":"006600"},{"value":220,"description":"Broadleaf","color":"00cc00"},{"value":230,"description":"Mixedwood","color":"cc9900"}],"gee:min":1,"gee:max":255}],"gee:cadence":["year"],"gee:terms_of_use":["Contains information licensed under the [Open Government Licence – Canada,\nversion 2.0](https://open.canada.ca/en/open-government-licence-canada)\n"],"gee:visualizations":[{"image_visualization":{"band_vis":{"bands":["landcover"],"max":[255],"min":[0],"palette":["000000","3333ff","996666","cc6699","e1e1e1","ffff00","993399","cccc00","cc6600","ffcc33","7899f6","ff9900","660000","dae31d","d6cc00","d2db25","d1d52b","cace32","c3c63a","b9bc44","a7b34d","b9c64e","999900","92a55b","809769","ffff99","98887c","799b93","5ea263","52ae77","41bf7a","d6ff70","8c8cff","d6cc00","ff7f00","315491","cc9933","896e43","8f6c3d","82654a","b85900","b74b15","ff8a8a","ffcccc","6f55ca","ffccff","dc5424","d05a30","d20000","cc0000","dc3200","ff6666","c5453b","7442bd","ffcccc","b5fb05","ccff05","07f98c","00ffcc","cc33cc","8e7672","b1954f","749a66","009900","006600","00cc00","cc9900"]}},"display_name":"Crop Landcover","lookat":{"zoom":10,"lat":53.0371,"lon":-103.8881}}]},"sci:citation":"Agriculture and Agri-Food Canada Annual Crop Inventory. {YEAR}","cube:dimensions":{"x":{"type":"spatial","axis":"x","extent":[-135.17,-51.24]},"y":{"type":"spatial","axis":"y","extent":[36.83,62.25]},"t":{"type":"temporal","extent":["2009-01-01T00:00:00Z",null]},"bands":{"type":"bands","values":["landcover"]}},"stac_extensions":["datacube","scientific","version"]};

const TESTPROCESS = {"id":"min","summary":"Minimum value","description":"Computes the smallest value of an array of numbers, which is is equal to the last element of a sorted (i.e., ordered) version the array.","categories":["math","reducer"],"parameters":[{"name":"data","description":"An array of numbers. An empty array resolves always with `null`.","schema":{"type":"array","items":{"type":["number","null"]}},"optional":true}],"returns":{"description":"The minimum value.","schema":{"type":["number","null"]}},"examples":[{"arguments":{"data":[1,0,3,2]},"returns":0},{"arguments":{"data":[5,2.5,null,-0.7]},"returns":-0.7},{"arguments":{"data":[1,0,3,null,2]},"returns":null},{"arguments":{"data":[]},"returns":null}],"links":[{"rel":"about","href":"http://mathworld.wolfram.com/Minimum.html","title":"Minimum explained by Wolfram MathWorld"}]};
const TESTPROCESS = {"id":"min","summary":"Minimum value","description":"Computes the smallest value of an array of numbers, which is is equal to the last element of a sorted (i.e., ordered) version the array.","categories":["math","reducer"],"parameters":[{"name":"data","description":"An array of numbers. An empty array resolves always with `null`.","schema":{"type":"array","items":{"type":["number","null"]}}}],"returns":{"description":"The minimum value.","schema":{"type":["number","null"]}},"examples":[{"arguments":{"data":[1,0,3,2]},"returns":0},{"arguments":{"data":[5,2.5,null,-0.7]},"returns":-0.7},{"arguments":{"data":[1,0,3,null,2]},"returns":null},{"arguments":{"data":[]},"returns":null}],"links":[{"rel":"about","href":"http://mathworld.wolfram.com/Minimum.html","title":"Minimum explained by Wolfram MathWorld"}]};

const PROCESSGRAPH = {"1":{"process_id":"load_collection","arguments":{"id":"IDAHO_EPSCOR/TERRACLIMATE","spatial_extent":null,"temporal_extent":["2017-07-01T00:00:00Z","2017-07-31T23:59:59Z"],"bands":["tmmx"]}},"2":{"process_id":"save_result","arguments":{"data":{"from_node":"3"},"format":"PNG","options":{}},"result":true},"3":{"process_id":"apply","arguments":{"data":{"from_node":"1"},"process":{"process_graph":{"2":{"process_id":"linear_scale_range","arguments":{"x":{"from_parameter":"x"},"inputMin":-150,"inputMax":450,"outputMax":255},"result":true}}}}}};
const VALID_PROCESS = {"process_graph":PROCESSGRAPH};
Expand All @@ -32,8 +32,7 @@ describe('With earth-engine-driver', () => {

async function connectWithBasicAuth() {
let con = await OpenEO.connect(TESTBACKEND);
let providers = await con.listAuthProviders();
await providers.basic.login(TESTUSERNAME, TESTPASSWORD);
await con.authenticateBasic(TESTUSERNAME, TESTPASSWORD);
return con;
}

Expand Down Expand Up @@ -81,8 +80,10 @@ describe('With earth-engine-driver', () => {
test('List providers', async () => {
expect(con instanceof Connection).toBeTruthy();
providers = await con.listAuthProviders();
expect(providers).toHaveProperty('basic');
basic = providers.basic;
expect(Array.isArray(providers)).toBeTruthy();
filtered = providers.filter(p => p.getType() === 'basic');
expect(filtered.length).toBe(1);
basic = filtered[0];
expect(basic instanceof BasicProvider).toBeTruthy();
expect(basic.getId()).toEqual('basic');
expect(basic.getToken()).toBeNull();
Expand Down Expand Up @@ -194,7 +195,9 @@ describe('With earth-engine-driver', () => {
var procs = await con.listProcesses();
expect(procs).toHaveProperty('processes');
expect(procs.processes.length).toBeGreaterThan(10);
expect(procs.processes.filter(x => x.id === 'min').length).toBe(1);
var min = procs.processes.filter(x => x.id === 'min');
expect(min.length).toBe(1);
expect(min[0]).toEqual(TESTPROCESS);
expect(procs.processes).toContainEqual(TESTPROCESS);
});

Expand Down

0 comments on commit d876586

Please sign in to comment.