diff --git a/webapp/cloudy.html b/webapp/cloudy.html new file mode 100644 index 0000000..b844658 --- /dev/null +++ b/webapp/cloudy.html @@ -0,0 +1,318 @@ + + + + NDVI Viewer + + + + + + + +
+
+ +
2024-01-01
+
+
+
+

S2

+
NDVI Timeseries
+ +
RGB Imagery
+
+
NDVI Imagery
+
+
+
+

S3

+
NDVI Timeseries
+ +
RGB Imagery
+
+
NDVI Imagery
+
+
+
+
+ + + diff --git a/webapp/index.html b/webapp/index.html index cdf76e8..e3be82b 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -45,6 +45,17 @@
+
+

Fusion

+
NDVI Timeseries
+ +
RGB Imagery
+
+
+
NDVI Imagery
+
+
+

S3

NDVI Timeseries
@@ -70,32 +81,35 @@ const mapOpts = { zoomControl: false }; const maps = { s2: L.map("s2map", mapOpts).setView([47.27, 11.39], 12).addLayer(L.tileLayer(osmUrl, osmOpts)), + fusion: L.map("fusionmap", mapOpts).setView([47.27, 11.39], 12).addLayer(L.tileLayer(osmUrl, osmOpts)), s3: L.map("s3map", mapOpts).setView([47.27, 11.39], 12).addLayer(L.tileLayer(osmUrl, osmOpts)) }; const ndvimaps = { s2: L.map("s2ndvimap", mapOpts).setView([47.27, 11.39], 12).addLayer(L.tileLayer(osmUrl, osmOpts)), + fusion: L.map("fusionndvimap", mapOpts).setView([47.27, 11.39], 12).addLayer(L.tileLayer(osmUrl, osmOpts)), s3: L.map("s3ndvimap", mapOpts).setView([47.27, 11.39], 12).addLayer(L.tileLayer(osmUrl, osmOpts)) }; - const overlays = { s2: null, s3: null }; - const ndviOverlays = { s2: null, s3: null }; - let timeseries = { s2: [], s3: [] }; + const overlays = { s2: null, fusion: null, s3: null }; + const ndviOverlays = { s2: null, fusion: null, s3: null }; + let timeseries = { s2: [], fusion: [], s3: [] }; let clouds = { s2: new Set(), s3: new Set() }; const showCloudsCheckbox = document.getElementById("showClouds"); async function loadTimeseries() { - const [s2, s3, cloudData] = await Promise.all([ + const [s2, fusion, s3, cloudData] = await Promise.all([ fetch("../data/innsbruck/2024/ndvi/s2/timeseries.json").then(r => r.json()), + fetch("../data/innsbruck/2024/ndvi/fusion/timeseries.json").then(r => r.json()).catch(() => []), fetch("../data/innsbruck/2024/ndvi/s3/timeseries.json").then(r => r.json()), fetch("../data/innsbruck/2024/clouds.json").then(r => r.json()).catch(() => ({ s2: [], s3: [] })) ]); - timeseries = { s2, s3 }; + timeseries = { s2, fusion, s3 }; clouds = { s2: new Set(cloudData.s2 || []), s3: new Set(cloudData.s3 || []) }; drawTimeseries(); } function drawTimeseries() { const currentDate = dateFromDays(parseInt(slider.value)); - for (const source of ["s2", "s3"]) { + for (const source of ["s2", "fusion", "s3"]) { const canvas = document.getElementById(`${source}timeseries`); const ctx = canvas.getContext("2d"); canvas.width = canvas.offsetWidth; @@ -106,7 +120,7 @@ ctx.clearRect(0, 0, w, h); let data = timeseries[source].filter(t => t.ndvi !== null); - if (!showCloudsCheckbox.checked) { + if (!showCloudsCheckbox.checked && clouds[source]) { data = data.filter(t => !clouds[source].has(t.filename)); } if (!data.length) continue; @@ -136,7 +150,7 @@ ctx.fillText(minNdvi.toFixed(2), 2, pad + plotH + 10); ctx.fillText(maxNdvi.toFixed(2), 2, pad + 3); - ctx.strokeStyle = source === "s2" ? "#0066ff" : "#ff6600"; + ctx.strokeStyle = source === "s2" ? "#0066ff" : source === "fusion" ? "#00aa00" : "#ff6600"; ctx.beginPath(); let first = true; for (const t of data) { @@ -173,13 +187,21 @@ const d = new Date(target); d.setDate(d.getDate() + offset * dir); const date = d.toISOString().split("T")[0].replace(/-/g, ""); - for (let i = 0; i < 3; i++) { - const filename = `${date}_${i}.geotiff`; - if (!showCloudsCheckbox.checked && clouds[source].has(filename)) continue; + if (source === "fusion") { + const filename = `REFL_${date}.tif`; try { - const res = await fetch(`../data/innsbruck/2024/${source}/${filename}`); + const res = await fetch(`../data/innsbruck/2024/efast/fusion/${filename}`); if (res.ok) return filename; } catch {} + } else { + for (let i = 0; i < 3; i++) { + const filename = `${date}_${i}.geotiff`; + if (!showCloudsCheckbox.checked && clouds[source] && clouds[source].has(filename)) continue; + try { + const res = await fetch(`../data/innsbruck/2024/${source}/${filename}`); + if (res.ok) return filename; + } catch {} + } } } } @@ -192,7 +214,8 @@ } async function loadGeotiff(source, filename) { - const tiff = await GeoTIFF.fromArrayBuffer(await (await fetch(`../data/innsbruck/2024/${source}/${filename}`)).arrayBuffer()); + const path = source === "fusion" ? `../data/innsbruck/2024/efast/fusion/${filename}` : `../data/innsbruck/2024/${source}/${filename}`; + const tiff = await GeoTIFF.fromArrayBuffer(await (await fetch(path)).arrayBuffer()); const image = await tiff.getImage(); const rasters = await image.readRasters(); const width = image.getWidth(); @@ -236,7 +259,7 @@ overlays[source] = L.imageOverlay(canvas.toDataURL(), bounds, { opacity: 0.95 }).addTo(maps[source]); maps[source].fitBounds(bounds); - const dateStr = filename.split("_")[0]; + const dateStr = source === "fusion" ? filename.split("_")[1] : filename.split("_")[0]; const date = `${dateStr.slice(0,4)}-${dateStr.slice(4,6)}-${dateStr.slice(6,8)}`; document.getElementById(`${source}rgbdate`).textContent = date; } @@ -278,7 +301,7 @@ ndviOverlays[source] = L.imageOverlay(canvas.toDataURL(), bounds, { opacity: 0.95 }).addTo(ndvimaps[source]); ndvimaps[source].fitBounds(bounds); - const dateStr = filename.split("_")[0]; + const dateStr = source === "fusion" ? filename.split("_")[0] : filename.split("_")[0]; const date = `${dateStr.slice(0,4)}-${dateStr.slice(4,6)}-${dateStr.slice(6,8)}`; document.getElementById(`${source}ndvidate`).textContent = date; } @@ -297,13 +320,21 @@ const d = new Date(target); d.setDate(d.getDate() + offset * dir); const date = d.toISOString().split("T")[0].replace(/-/g, ""); - for (let i = 0; i < 3; i++) { - const filename = `${date}_${i}.geotiff`; - if (!showCloudsCheckbox.checked && clouds[source].has(filename)) continue; + if (source === "fusion") { + const filename = `${date}_ndvi.geotiff`; try { - const res = await fetch(`../data/innsbruck/2024/ndvi/${source}/${filename}`); + const res = await fetch(`../data/innsbruck/2024/ndvi/fusion/${filename}`); if (res.ok) return filename; } catch {} + } else { + for (let i = 0; i < 3; i++) { + const filename = `${date}_${i}.geotiff`; + if (!showCloudsCheckbox.checked && clouds[source] && clouds[source].has(filename)) continue; + try { + const res = await fetch(`../data/innsbruck/2024/ndvi/${source}/${filename}`); + if (res.ok) return filename; + } catch {} + } } } } @@ -318,7 +349,7 @@ if (!showCloudsCheckbox.checked) params.set("hideClouds", "1"); history.replaceState({}, "", `?${params}`); drawTimeseries(); - for (const source of ["s2", "s3"]) { + for (const source of ["s2", "fusion", "s3"]) { const filename = await findFile(date, source); if (filename) { try {