Skip to content

Commit 6e43eec

Browse files
authored
feature: add links for render parameters and /cog/map link to /cog/viewer dashboard (#987)
* add buttons for sharing parameters and a link * print arrays instead of strings, fix 3-band params * only show 'share' button when enable_viewer=True * simplify viewer_enabled logic
1 parent 4327ab8 commit 6e43eec

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

src/titiler/extensions/titiler/extensions/templates/cog_viewer.html

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@
6161
display: block;
6262
padding: 5px;
6363
}
64+
.share-button.hidden {
65+
display: none !important;
66+
}
6467
#menu {
6568
left: 0;
6669
top: 0;
@@ -291,6 +294,29 @@
291294
<table id="histogram-table" class="none"></table>
292295
</div>
293296

297+
<div class="px6 py6 w-full">
298+
<div class="txt-h5 color-black">
299+
<svg class="icon icon--l inline-block">
300+
<use xlink:href="#icon-share" />
301+
</svg>
302+
Share
303+
</div>
304+
<div id="export-div" class="w-full align-center">
305+
<button
306+
id="btn-export"
307+
class="btn bts--xs btn--stroke bg-darken25-on-hover inline-block txt-s color-black mx12 my12"
308+
>
309+
Show Render Parameters
310+
</button>
311+
<button
312+
id="btn-share-link"
313+
class="btn bts--xs btn--stroke bg-darken25-on-hover inline-block txt-s color-black mx12 my12 share-button"
314+
>
315+
Share Map
316+
</button>
317+
</div>
318+
</div>
319+
</div>
294320
</div>
295321
<button id='btn-hide'><svg id='hide-arrow' class='icon'><use xlink:href='#icon-arrow-right'/></svg></button>
296322
</div>
@@ -318,6 +344,7 @@
318344
const tilejson_endpoint = '{{ tilejson_endpoint }}'
319345
const info_endpoint = '{{ info_endpoint }}'
320346
const stats_endpoint = '{{ statistics_endpoint }}'
347+
const viewer_enabled = '{{ viewer_enabled|tojson }}'
321348

322349
const dtype_ranges = {
323350
'int8': [-128, 127],
@@ -330,6 +357,28 @@
330357
'float64': [-1.7976931348623157e+308, 1.7976931348623157e+308]
331358
}
332359

360+
function updateShareButtonVisibility() {
361+
console.log('updateShareButtonVisibility called');
362+
console.log('viewer_enabled:', viewer_enabled);
363+
364+
const shareButton = document.getElementById('btn-share-link');
365+
if (!shareButton) {
366+
console.log('Share button not found in the DOM');
367+
return;
368+
}
369+
370+
console.log('shareButton:', shareButton);
371+
372+
if (viewer_enabled === 'true') {
373+
console.log('Setting button to visible');
374+
shareButton.classList.remove('hidden');
375+
} else {
376+
console.log('Setting button to hidden');
377+
shareButton.classList.add('hidden');
378+
}
379+
}
380+
updateShareButtonVisibility();
381+
333382
var map = new maplibregl.Map({
334383
container: 'map',
335384
style: {
@@ -914,6 +963,111 @@
914963
addCogeo()
915964
}
916965
})
966+
967+
document.getElementById('btn-share-link').addEventListener('click', () => {
968+
const rasterType = document.getElementById("toolbar").querySelector(".active").id;
969+
970+
let params = new URLSearchParams();
971+
params.append('url', scope.url);
972+
973+
if (rasterType === "1b") {
974+
975+
params.append('bidx', document.getElementById("layer-selector").selectedOptions[0].getAttribute("bidx"));
976+
const colormap_name = document.getElementById('colormap-selector').value;
977+
if (colormap_name != "b&w") {
978+
params.append('colormap_name', colormap_name);
979+
}
980+
} else if (rasterType === "3b") {
981+
params.append('bidx', document.getElementById("r-selector").selectedOptions[0].getAttribute("bidx"));
982+
params.append('bidx', document.getElementById("g-selector").selectedOptions[0].getAttribute("bidx"));
983+
params.append('bidx', document.getElementById("b-selector").selectedOptions[0].getAttribute("bidx"));
984+
}
985+
986+
// Add rescale parameter for both 1b and 3b if applicable
987+
if (["uint8", "int8"].indexOf(scope.data_type) === -1 && !scope.colormap) {
988+
params.append('rescale', `${document.getElementById("data-min").value},${document.getElementById("data-max").value}`);
989+
}
990+
991+
const path_name = `${window.location.pathname}`.replace("viewer", "WebMercatorQuad/map");
992+
const shareUrl = `${window.location.origin}${path_name}?${params.toString()}`;
993+
994+
// Create a temporary input element to copy the URL
995+
const tempInput = document.createElement('input');
996+
tempInput.value = shareUrl;
997+
document.body.appendChild(tempInput);
998+
tempInput.select();
999+
document.execCommand('copy');
1000+
document.body.removeChild(tempInput);
1001+
1002+
alert('Share link copied to clipboard!');
1003+
});
1004+
1005+
document.getElementById('btn-export').addEventListener('click', () => {
1006+
const rasterType = document.getElementById("toolbar").querySelector(".active").id;
1007+
let params = {};
1008+
1009+
if (rasterType === "1b") {
1010+
// Convert bidx to a single-element array
1011+
params.bidx = [parseInt(document.getElementById("layer-selector").selectedOptions[0].getAttribute("bidx"))];
1012+
1013+
const colormap_name = document.getElementById('colormap-selector').value;
1014+
if (colormap_name !== "b&w") {
1015+
params.colormap_name = colormap_name;
1016+
}
1017+
} else if (rasterType === "3b") {
1018+
params.bidx = [
1019+
parseFloat(document.getElementById("r-selector").selectedOptions[0].getAttribute("bidx")),
1020+
parseFloat(document.getElementById("g-selector").selectedOptions[0].getAttribute("bidx")),
1021+
parseFloat(document.getElementById("b-selector").selectedOptions[0].getAttribute("bidx")),
1022+
]
1023+
}
1024+
1025+
// Add rescale parameter for both 1b and 3b if applicable
1026+
if (["uint8", "int8"].indexOf(scope.data_type) === -1 && !scope.colormap) {
1027+
// Convert rescale to a nested array
1028+
params.rescale = [[
1029+
parseFloat(document.getElementById("data-min").value),
1030+
parseFloat(document.getElementById("data-max").value)
1031+
]];
1032+
}
1033+
1034+
showJsonPopup(params);
1035+
});
1036+
function showJsonPopup(jsonContent) {
1037+
const popup = document.createElement('div');
1038+
popup.style.position = 'fixed';
1039+
popup.style.left = '50%';
1040+
popup.style.top = '50%';
1041+
popup.style.transform = 'translate(-50%, -50%)';
1042+
popup.style.backgroundColor = 'white';
1043+
popup.style.padding = '30px 20px 20px'; // Increased top padding for close button
1044+
popup.style.border = '1px solid black';
1045+
popup.style.zIndex = '1000';
1046+
popup.style.borderRadius = '5px'; // Optional: rounded corners
1047+
popup.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)'; // Optional: shadow for depth
1048+
1049+
const closeButton = document.createElement('button');
1050+
closeButton.textContent = '×'; // Using '×' character for close
1051+
closeButton.style.position = 'absolute';
1052+
closeButton.style.right = '10px';
1053+
closeButton.style.top = '10px';
1054+
closeButton.style.border = 'none';
1055+
closeButton.style.background = 'none';
1056+
closeButton.style.fontSize = '20px';
1057+
closeButton.style.cursor = 'pointer';
1058+
closeButton.style.color = '#333';
1059+
closeButton.onclick = () => document.body.removeChild(popup);
1060+
popup.appendChild(closeButton);
1061+
1062+
const pre = document.createElement('pre');
1063+
pre.textContent = JSON.stringify(jsonContent, null, 2);
1064+
pre.style.margin = '0'; // Remove default margins
1065+
pre.style.whiteSpace = 'pre-wrap'; // Allow text to wrap
1066+
pre.style.wordBreak = 'break-word'; // Break long words if necessary
1067+
popup.appendChild(pre);
1068+
1069+
document.body.appendChild(popup);
1070+
}
9171071
</script>
9181072
</body>
9191073
</html>

src/titiler/extensions/titiler/extensions/viewer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def cog_viewer(request: Request):
3636
),
3737
"info_endpoint": factory.url_for(request, "info"),
3838
"statistics_endpoint": factory.url_for(request, "statistics"),
39+
"viewer_enabled": getattr(factory, "add_viewer", False),
3940
},
4041
media_type="text/html",
4142
)

0 commit comments

Comments
 (0)