From f9b44da15f04699312077990c3418dea90bb484c Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 16:03:35 +0200 Subject: [PATCH 01/13] Add algorithms selection to /cog/viewer --- .../extensions/templates/cog_viewer.html | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index 04d37554b..dae5aa211 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -256,6 +256,17 @@
+ + +
+
Algorithm
+
+ + +
+
@@ -338,7 +349,8 @@ dataset_statistics: undefined, data_type: undefined, band_descriptions: undefined, - colormap: undefined + colormap: undefined, + algorithms: undefined, } const tilejson_endpoint = '{{ tilejson_endpoint }}' @@ -479,11 +491,20 @@ params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } + const algorithmSelector = document.getElementById('algorithm-selector'); + const algorithm = algorithmSelector.selectedOptions[0].value; + if (algorithm !== 'no-algo') { + params.algorithm = algorithm + params.algorithm_params = JSON.stringify({}) + } + // const params = scope.algorithms[selected]['parameters']; + const cmap = document.getElementById('colormap-selector')[document.getElementById('colormap-selector').selectedIndex] if (cmap.value !== 'b&w') params.colormap_name = cmap.value const url_params = Object.keys(params).map(i => `${i}=${params[i]}`).join('&') let url = `${tilejson_endpoint}?${url_params}` + console.log(url) setMapLayers(url) if (scope.dataset_statistics) addHisto1Band() } @@ -841,7 +862,6 @@ throw new Error('Network response was not ok.') }) .then(data => { - console.log(data) scope.data_type = data.properties.dtype scope.colormap = data.properties.colormap @@ -910,6 +930,63 @@ .catch(err => { console.warn(err) }) + + + // fetch(`/colorMaps`) then /colorMaps/accent?format=png but one request per colormap pretty heavy + fetch(`/algorithms`) + .then(res => { + if (res.ok) return res.json() + throw new Error('Network response was not ok.') + }) + .then(algorithms => { + // console.log('ALGORITHMS', algorithms) + scope.algorithms = algorithms; + const algorithmSelector = document.getElementById('algorithm-selector'); + for (const algo_id in algorithms) { + const algo = algorithms[algo_id]; + const opt = document.createElement('option'); + opt.value = algo_id; + opt.innerHTML = algo['title']; + algorithmSelector.appendChild(opt); + } + algorithmSelector.addEventListener('change', updateAlgorithmParams); + }) + .catch(err => { + console.warn(err); + }) +} + +function updateAlgorithmParams() { + const algorithmSelector = document.getElementById('algorithm-selector'); + const selected = algorithmSelector.selectedOptions[0].value; + const params = scope.algorithms[selected]['parameters']; + + // Recreate div to host params + const paramsElOld = Array.from(algorithmSelector.parentNode.children).find(el => el.id == 'algorithm-params'); + if (paramsElOld) { + paramsElOld.remove(); + } + // Reproduce the div + form from lat/lon inputs + const paramsEl = document.createElement('div'); + paramsEl.className = 'grid px12 py12 w-full grid'; + paramsEl.id = 'algorithm-params'; + algorithmSelector.parentNode.appendChild(paramsEl); + const paramsForm = document.createElement('form'); + paramsForm.className = 'grid grid--gut12 mx12 mt12'; + paramsForm.id = 'algorithm-params-form'; + paramsEl.appendChild(paramsForm); + for (const param_id in params) { + const param = params[param_id]; + const paramEl = document.createElement('div'); + paramEl.className = 'row'; + paramsForm.appendChild(paramEl); + paramEl.innerHTML = ` + + + `; + } + // Update to react to params change + updateViz(); } document.getElementById('launch').addEventListener('click', () => { From ab7026de68793888d5f2bfe4bd796689bf718c5c Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 16:35:39 +0200 Subject: [PATCH 02/13] Use algorithm params and update 1bviz --- .../titiler/extensions/templates/cog_viewer.html | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index dae5aa211..344425cae 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -495,7 +495,9 @@ const algorithm = algorithmSelector.selectedOptions[0].value; if (algorithm !== 'no-algo') { params.algorithm = algorithm - params.algorithm_params = JSON.stringify({}) + const params_inputs = document.getElementById('algorithm-params-form').getElementsByTagName('input') + algorithm_params = Object.fromEntries(Array.from(params_inputs).map(e => [e.name, e.value])) + params.algorithm_params = JSON.stringify(algorithm_params) } // const params = scope.algorithms[selected]['parameters']; @@ -962,17 +964,17 @@ const params = scope.algorithms[selected]['parameters']; // Recreate div to host params - const paramsElOld = Array.from(algorithmSelector.parentNode.children).find(el => el.id == 'algorithm-params'); + const paramsElOld = Array.from(algorithmSelector.parentNode.parentNode.children).find(el => el.id == 'algorithm-params'); if (paramsElOld) { paramsElOld.remove(); } // Reproduce the div + form from lat/lon inputs const paramsEl = document.createElement('div'); - paramsEl.className = 'grid px12 py12 w-full grid'; + paramsEl.className = 'grid w-full'; paramsEl.id = 'algorithm-params'; - algorithmSelector.parentNode.appendChild(paramsEl); + algorithmSelector.parentNode.parentNode.appendChild(paramsEl); const paramsForm = document.createElement('form'); - paramsForm.className = 'grid grid--gut12 mx12 mt12'; + paramsForm.className = 'grid'; paramsForm.id = 'algorithm-params-form'; paramsEl.appendChild(paramsForm); for (const param_id in params) { @@ -981,8 +983,8 @@ paramEl.className = 'row'; paramsForm.appendChild(paramEl); paramEl.innerHTML = ` - - + + `; } // Update to react to params change From f4ce9c7ab9b8781858c07a43a4b3d1fc2059ac1b Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 16:56:16 +0200 Subject: [PATCH 03/13] Remove non-1b algorithms --- .../titiler/extensions/templates/cog_viewer.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index 344425cae..37a78c344 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -264,7 +264,7 @@ - +
@@ -499,7 +499,6 @@ algorithm_params = Object.fromEntries(Array.from(params_inputs).map(e => [e.name, e.value])) params.algorithm_params = JSON.stringify(algorithm_params) } - // const params = scope.algorithms[selected]['parameters']; const cmap = document.getElementById('colormap-selector')[document.getElementById('colormap-selector').selectedIndex] if (cmap.value !== 'b&w') params.colormap_name = cmap.value @@ -942,10 +941,15 @@ }) .then(algorithms => { // console.log('ALGORITHMS', algorithms) - scope.algorithms = algorithms; + // only select algorithms applicable to 1d inputs, like DEM: + const algorithms_arr = Object.entries(algorithms); + const filtered = algorithms_arr.filter(([algo_id, algo]) => algo.inputs.nbands == 1); + const algorithms_filtered = Object.fromEntries(filtered); + + scope.algorithms = algorithms_filtered; const algorithmSelector = document.getElementById('algorithm-selector'); - for (const algo_id in algorithms) { - const algo = algorithms[algo_id]; + for (const algo_id in algorithms_filtered) { + const algo = algorithms_filtered[algo_id]; const opt = document.createElement('option'); opt.value = algo_id; opt.innerHTML = algo['title']; From f53b1a1c6d9551d701c7687391c75ec537c365d5 Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 17:37:04 +0200 Subject: [PATCH 04/13] Generalize algorithms for 1b & 3b The algorithms not applicable to 3b or 1b or disabled in the selector within the updateViz function --- .../extensions/templates/cog_viewer.html | 86 +++++++++++++------ 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index 37a78c344..d1b85d6be 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -256,19 +256,19 @@
- - -
-
Algorithm
-
- -
-
-
+ +
+
Algorithm
+
+ +
+
+
+
Rescale
@@ -481,6 +481,18 @@ }) } +const setAlgorithmParams = (params) => { + const algorithmSelector = document.getElementById('algorithm-selector'); + const algorithm = algorithmSelector.selectedOptions[0].value; + if (algorithm !== 'no-algo') { + params.algorithm = algorithm + const params_inputs = document.getElementById('algorithm-params-form').getElementsByTagName('input') + algorithm_params = Object.fromEntries(Array.from(params_inputs).map(e => [e.name, e.value])) + params.algorithm_params = JSON.stringify(algorithm_params) + } + return params +} + const set1bViz = () => { params = { url: scope.url @@ -491,14 +503,7 @@ params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } - const algorithmSelector = document.getElementById('algorithm-selector'); - const algorithm = algorithmSelector.selectedOptions[0].value; - if (algorithm !== 'no-algo') { - params.algorithm = algorithm - const params_inputs = document.getElementById('algorithm-params-form').getElementsByTagName('input') - algorithm_params = Object.fromEntries(Array.from(params_inputs).map(e => [e.name, e.value])) - params.algorithm_params = JSON.stringify(algorithm_params) - } + params = setAlgorithmParams(params) const cmap = document.getElementById('colormap-selector')[document.getElementById('colormap-selector').selectedIndex] if (cmap.value !== 'b&w') params.colormap_name = cmap.value @@ -521,6 +526,9 @@ if (['uint8','int8'].indexOf(scope.data_type) === -1 && !scope.colormap) { params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } + + params = setAlgorithmParams(params) + let url_params = Object.keys(params).map(i => `${i}=${params[i]}`).join('&') if (url_params !== '') url_params = `${url_params}&` @@ -532,6 +540,34 @@ const updateViz = () => { const rasterType = document.getElementById('toolbar').querySelector(".active").id + + // only select algorithms applicable to 1d or 3d inputs + const algorithms_arr = Object.entries(scope.algorithms); + const filtered_1b = algorithms_arr.filter(([algo_id, algo]) => (algo.inputs.nbands === 1) || (algo.inputs.nbands === null)); + const algorithms_filtered_1b = Object.fromEntries(filtered_1b); + const filtered_3b = algorithms_arr.filter(([algo_id, algo]) => (algo.inputs.nbands >= 2) || (algo.inputs.nbands === null)); + const algorithms_filtered_3b = Object.fromEntries(filtered_3b); + const algorithmOptions = Array.from(document.getElementById('algorithm-selector').getElementsByTagName('option')); + for (o of algorithmOptions) {o.disabled = true} + document.getElementById('no-algo').disabled = false + console.log('3b', '1b', filtered_3b, filtered_1b) + switch (rasterType) { + case '1b': + console.log('1b') + for (const algo_id in algorithms_filtered_1b) { + algorithmOptions.find(o => o.value == algo_id).disabled = false + console.log('dedisabled', algo_id) + } + break + case '3b': + console.log('3b') + for (const algo_id in algorithms_filtered_3b) { + algorithmOptions.find(o => o.value == algo_id).disabled = false + console.log('dedisabled', algo_id) + } + break + } + switch (rasterType) { case '1b': set1bViz() @@ -941,15 +977,11 @@ }) .then(algorithms => { // console.log('ALGORITHMS', algorithms) - // only select algorithms applicable to 1d inputs, like DEM: - const algorithms_arr = Object.entries(algorithms); - const filtered = algorithms_arr.filter(([algo_id, algo]) => algo.inputs.nbands == 1); - const algorithms_filtered = Object.fromEntries(filtered); - - scope.algorithms = algorithms_filtered; + + scope.algorithms = algorithms; const algorithmSelector = document.getElementById('algorithm-selector'); - for (const algo_id in algorithms_filtered) { - const algo = algorithms_filtered[algo_id]; + for (const algo_id in algorithms) { + const algo = algorithms[algo_id]; const opt = document.createElement('option'); opt.value = algo_id; opt.innerHTML = algo['title']; From 135b5321175e242e5265bf27d8e30829d544f746 Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 17:41:40 +0200 Subject: [PATCH 05/13] touchups --- .../titiler/extensions/templates/cog_viewer.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index d1b85d6be..933f75029 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -502,7 +502,6 @@ if (['uint8','int8'].indexOf(scope.data_type) === -1 && !scope.colormap) { params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } - params = setAlgorithmParams(params) const cmap = document.getElementById('colormap-selector')[document.getElementById('colormap-selector').selectedIndex] @@ -510,7 +509,6 @@ const url_params = Object.keys(params).map(i => `${i}=${params[i]}`).join('&') let url = `${tilejson_endpoint}?${url_params}` - console.log(url) setMapLayers(url) if (scope.dataset_statistics) addHisto1Band() } @@ -526,7 +524,6 @@ if (['uint8','int8'].indexOf(scope.data_type) === -1 && !scope.colormap) { params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } - params = setAlgorithmParams(params) let url_params = Object.keys(params).map(i => `${i}=${params[i]}`).join('&') @@ -899,6 +896,7 @@ throw new Error('Network response was not ok.') }) .then(data => { + console.log(data) scope.data_type = data.properties.dtype scope.colormap = data.properties.colormap @@ -967,9 +965,7 @@ .catch(err => { console.warn(err) }) - - // fetch(`/colorMaps`) then /colorMaps/accent?format=png but one request per colormap pretty heavy fetch(`/algorithms`) .then(res => { if (res.ok) return res.json() @@ -977,7 +973,6 @@ }) .then(algorithms => { // console.log('ALGORITHMS', algorithms) - scope.algorithms = algorithms; const algorithmSelector = document.getElementById('algorithm-selector'); for (const algo_id in algorithms) { From 50cc8fec94b202663c6b0e2e7d517c38981b7d00 Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 17:48:59 +0200 Subject: [PATCH 06/13] Final touchups --- .../titiler/extensions/templates/cog_viewer.html | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index 933f75029..c68edbf52 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -487,7 +487,7 @@ if (algorithm !== 'no-algo') { params.algorithm = algorithm const params_inputs = document.getElementById('algorithm-params-form').getElementsByTagName('input') - algorithm_params = Object.fromEntries(Array.from(params_inputs).map(e => [e.name, e.value])) + const algorithm_params = Object.fromEntries(Array.from(params_inputs).map(e => [e.name, e.value])) params.algorithm_params = JSON.stringify(algorithm_params) } return params @@ -502,6 +502,7 @@ if (['uint8','int8'].indexOf(scope.data_type) === -1 && !scope.colormap) { params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } + params = setAlgorithmParams(params) const cmap = document.getElementById('colormap-selector')[document.getElementById('colormap-selector').selectedIndex] @@ -524,6 +525,7 @@ if (['uint8','int8'].indexOf(scope.data_type) === -1 && !scope.colormap) { params.rescale = `${document.getElementById('data-min').value},${document.getElementById('data-max').value}` } + params = setAlgorithmParams(params) let url_params = Object.keys(params).map(i => `${i}=${params[i]}`).join('&') @@ -547,20 +549,15 @@ const algorithmOptions = Array.from(document.getElementById('algorithm-selector').getElementsByTagName('option')); for (o of algorithmOptions) {o.disabled = true} document.getElementById('no-algo').disabled = false - console.log('3b', '1b', filtered_3b, filtered_1b) switch (rasterType) { case '1b': - console.log('1b') for (const algo_id in algorithms_filtered_1b) { algorithmOptions.find(o => o.value == algo_id).disabled = false - console.log('dedisabled', algo_id) } break case '3b': - console.log('3b') for (const algo_id in algorithms_filtered_3b) { algorithmOptions.find(o => o.value == algo_id).disabled = false - console.log('dedisabled', algo_id) } break } From 04029f9ff1f8fad8685cb6ef1fdce380af67305d Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 18:21:29 +0200 Subject: [PATCH 07/13] Make algorithm icon a car --- .../extensions/titiler/extensions/templates/cog_viewer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index c68edbf52..5f789fea8 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -260,7 +260,7 @@
-
Algorithm
+
Algorithm
From 0b7333a41e7a6c6ef3b7b94d63fef55023ce8230 Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 18:26:26 +0200 Subject: [PATCH 09/13] remove comment icon --- .../extensions/titiler/extensions/templates/cog_viewer.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index 82917d62c..b49772364 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -260,7 +260,6 @@
-
Algorithm
+
@@ -507,6 +513,10 @@ params = setAlgorithmParams(params) + if (expression && expression?.length > 0) { + params.expression = encodeURIComponent(expression) + } + const cmap = document.getElementById('colormap-selector')[document.getElementById('colormap-selector').selectedIndex] if (cmap.value !== 'b&w') params.colormap_name = cmap.value @@ -529,6 +539,10 @@ } params = setAlgorithmParams(params) + const expression = document.getElementById('expression').value + if (expression && expression?.length > 0) { + params.expression = expression + } let url_params = Object.keys(params).map(i => `${i}=${params[i]}`).join('&') if (url_params !== '') url_params = `${url_params}&` From 9884da4a642b415b1f1899f4e835735a9ea8dfff Mon Sep 17 00:00:00 2001 From: Jonathan Chemla Date: Wed, 2 Apr 2025 22:27:45 +0200 Subject: [PATCH 13/13] Forgot committing one-line --- .../extensions/titiler/extensions/templates/cog_viewer.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html index 1933dc3b1..ef12fda47 100644 --- a/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html +++ b/src/titiler/extensions/titiler/extensions/templates/cog_viewer.html @@ -513,6 +513,7 @@ params = setAlgorithmParams(params) + const expression = document.getElementById('expression').value if (expression && expression?.length > 0) { params.expression = encodeURIComponent(expression) } @@ -539,6 +540,7 @@ } params = setAlgorithmParams(params) + const expression = document.getElementById('expression').value if (expression && expression?.length > 0) { params.expression = expression