| |
| document.addEventListener("DOMContentLoaded", () => { |
| |
| |
| |
| const landingPage = document.getElementById("landing-page"); |
| const terminalPage = document.getElementById("terminal-page"); |
| const launchBtn = document.getElementById("launch-btn"); |
|
|
| launchBtn.addEventListener("click", () => { |
| landingPage.classList.add("slide-out"); |
| setTimeout(() => { |
| landingPage.style.display = "none"; |
| terminalPage.classList.add("active"); |
| |
| if (map) { |
| map.invalidateSize(); |
| } |
| }, 600); |
| }); |
|
|
| |
| |
| |
| const navTabs = document.querySelectorAll(".nav-tab"); |
| const tabContents = document.querySelectorAll(".tab-content"); |
|
|
| navTabs.forEach(tab => { |
| tab.addEventListener("click", () => { |
| navTabs.forEach(t => t.classList.remove("active")); |
| tabContents.forEach(c => c.classList.remove("active")); |
|
|
| tab.classList.add("active"); |
| const activeTabId = tab.getAttribute("data-tab"); |
| document.getElementById(activeTabId).classList.add("active"); |
|
|
| |
| if (activeTabId === "search-pane" && map) { |
| setTimeout(() => map.invalidateSize(), 50); |
| } |
| |
| if (activeTabId === "benchmarks-pane") { |
| loadBenchmarks(); |
| setTimeout(() => { |
| if (window.MathJax && window.MathJax.typesetPromise) { |
| window.MathJax.typesetPromise(); |
| } |
| }, 100); |
| } |
| }); |
| }); |
|
|
| |
| |
| |
| const modeImageBtn = document.getElementById("mode-image-btn"); |
| const modeTextBtn = document.getElementById("mode-text-btn"); |
| const imageUploadArea = document.getElementById("image-upload-area"); |
| const textQueryArea = document.getElementById("text-query-area"); |
| let activeSearchMode = "image"; |
|
|
| const retrievalLevelSelect = document.getElementById("retrieval-level"); |
| const spatialOptionsGroup = document.getElementById("spatial-options-group"); |
|
|
| function toggleSpatialOptions() { |
| if (retrievalLevelSelect.value === "level4") { |
| spatialOptionsGroup.style.display = "block"; |
| } else { |
| spatialOptionsGroup.style.display = "none"; |
| } |
| } |
|
|
| retrievalLevelSelect.addEventListener("change", toggleSpatialOptions); |
| toggleSpatialOptions(); |
|
|
| modeImageBtn.addEventListener("click", () => { |
| modeImageBtn.classList.add("active"); |
| modeTextBtn.classList.remove("active"); |
| imageUploadArea.style.display = "block"; |
| textQueryArea.style.display = "none"; |
| activeSearchMode = "image"; |
| }); |
|
|
| modeTextBtn.addEventListener("click", () => { |
| modeTextBtn.classList.add("active"); |
| modeImageBtn.classList.remove("active"); |
| imageUploadArea.style.display = "none"; |
| textQueryArea.style.display = "block"; |
| activeSearchMode = "text"; |
| }); |
|
|
| |
| |
| |
| const dropZone = document.getElementById("drop-zone"); |
| const fileInput = document.getElementById("file-input"); |
| const uploadPreview = document.getElementById("upload-preview"); |
| const previewImg = document.getElementById("preview-img"); |
| const previewFilename = document.getElementById("preview-filename"); |
| const previewSize = document.getElementById("preview-size"); |
| const clearUpload = document.getElementById("clear-upload"); |
| let uploadedFile = null; |
|
|
| dropZone.addEventListener("click", () => fileInput.click()); |
|
|
| dropZone.addEventListener("dragover", (e) => { |
| e.preventDefault(); |
| dropZone.style.borderColor = "var(--primary-color)"; |
| dropZone.style.backgroundColor = "var(--primary-glow)"; |
| }); |
|
|
| dropZone.addEventListener("dragleave", () => { |
| dropZone.style.borderColor = "var(--border-color)"; |
| dropZone.style.backgroundColor = "transparent"; |
| }); |
|
|
| dropZone.addEventListener("drop", (e) => { |
| e.preventDefault(); |
| dropZone.style.borderColor = "var(--border-color)"; |
| dropZone.style.backgroundColor = "transparent"; |
| if (e.dataTransfer.files.length > 0) { |
| handleFile(e.dataTransfer.files[0]); |
| } |
| }); |
|
|
| fileInput.addEventListener("change", (e) => { |
| if (e.target.files.length > 0) { |
| handleFile(e.target.files[0]); |
| } |
| }); |
|
|
| clearUpload.addEventListener("click", (e) => { |
| e.stopPropagation(); |
| uploadedFile = null; |
| fileInput.value = ""; |
| previewImg.src = ""; |
| uploadPreview.style.display = "none"; |
| dropZone.style.display = "block"; |
| }); |
|
|
| function handleFile(file) { |
| uploadedFile = file; |
| previewFilename.textContent = file.name; |
| |
| |
| const sizeMB = (file.size / (1024 * 1024)).toFixed(1); |
| previewSize.textContent = `${sizeMB} MB`; |
|
|
| |
| const isTiff = file.name.endsWith(".tif") || file.name.endsWith(".tiff"); |
| |
| if (isTiff) { |
| |
| previewImg.src = `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100"><rect width="100" height="100" rx="10" fill="%23f8fafc" stroke="%23cbd5e1" stroke-width="2"/><path d="M35 25 H55 L65 35 V75 H35 Z" fill="white" stroke="%233b82f6" stroke-width="2"/><path d="M55 25 V35 H65" fill="none" stroke="%233b82f6" stroke-width="2"/><text x="50" y="60" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" fill="%231e293b" text-anchor="middle">GeoTIFF</text></svg>`; |
| } else { |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| previewImg.src = e.target.result; |
| }; |
| reader.readAsDataURL(file); |
| } |
|
|
| dropZone.style.display = "none"; |
| uploadPreview.style.display = "block"; |
| } |
|
|
| |
| |
| |
| let map; |
| let centerMarker; |
| let searchRadiusCircle; |
| let resultsMarkersGroup = L.layerGroup(); |
| let h3GridGroup = L.layerGroup(); |
|
|
| const indiaCenter = [20.5937, 78.9629]; |
|
|
| function initMap() { |
| const mapEl = document.getElementById("map"); |
| if (!mapEl) return; |
| |
| map = L.map("map").setView(indiaCenter, 5); |
|
|
| |
| L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', { |
| attribution: 'Tiles © Esri — Sources: Esri, DeLorme, NAVTEQ, USGS, NOAA, and the GIS User Community' |
| }).addTo(map); |
|
|
| |
| centerMarker = L.marker(indiaCenter, { draggable: true }).addTo(map); |
| |
| |
| updateMapCircle(indiaCenter, parseInt(document.getElementById("radius-input").value)); |
|
|
| |
| centerMarker.on("dragend", (e) => { |
| const latlng = e.target.getLatLng(); |
| document.getElementById("lat-input").value = latlng.lat.toFixed(5); |
| document.getElementById("lon-input").value = latlng.lng.toFixed(5); |
| updateMapCircle([latlng.lat, latlng.lng], parseInt(document.getElementById("radius-input").value)); |
| }); |
|
|
| |
| map.on("click", (e) => { |
| const latlng = e.latlng; |
| centerMarker.setLatLng(latlng); |
| document.getElementById("lat-input").value = latlng.lat.toFixed(5); |
| document.getElementById("lon-input").value = latlng.lng.toFixed(5); |
| updateMapCircle([latlng.lat, latlng.lng], parseInt(document.getElementById("radius-input").value)); |
| }); |
|
|
| resultsMarkersGroup.addTo(map); |
| h3GridGroup.addTo(map); |
| } |
|
|
| function updateMapCircle(coords, radiusKm) { |
| if (!map) return; |
| if (searchRadiusCircle) { |
| map.removeLayer(searchRadiusCircle); |
| } |
| searchRadiusCircle = L.circle(coords, { |
| radius: radiusKm * 1000, |
| color: "#2563eb", |
| fillColor: "#3b82f6", |
| fillOpacity: 0.1, |
| weight: 1.5 |
| }).addTo(map); |
| } |
|
|
| |
| const radiusInput = document.getElementById("radius-input"); |
| const radiusVal = document.getElementById("radius-val"); |
| radiusInput.addEventListener("input", (e) => { |
| const val = e.target.value; |
| radiusVal.textContent = `${val} km`; |
| if (map) { |
| const lat = parseFloat(document.getElementById("lat-input").value); |
| const lon = parseFloat(document.getElementById("lon-input").value); |
| updateMapCircle([lat, lon], parseInt(val)); |
| } |
| }); |
|
|
| const kInput = document.getElementById("k-input"); |
| const kVal = document.getElementById("k-val"); |
| kInput.addEventListener("input", (e) => { |
| kVal.textContent = e.target.value; |
| }); |
|
|
| initMap(); |
|
|
| |
| |
| |
| const searchBtn = document.getElementById("search-btn"); |
| const resultsEmpty = document.getElementById("results-empty"); |
| const resultsGrid = document.getElementById("results-grid"); |
| const resultsTableContainer = document.getElementById("results-table-container"); |
| const resultsTableBody = document.getElementById("results-table-body"); |
| const timingFeed = document.getElementById("timing-feed"); |
|
|
| searchBtn.addEventListener("click", () => { |
| if (activeSearchMode === "image" && !uploadedFile) { |
| alert("Please upload a query satellite image first."); |
| return; |
| } |
| if (activeSearchMode === "text" && !document.getElementById("text-query-input").value.trim()) { |
| alert("Please enter a text search query."); |
| return; |
| } |
|
|
| searchBtn.disabled = true; |
| searchBtn.innerHTML = `<i class="fa-solid fa-circle-notch fa-spin"></i> EXECUTING RETRIEVAL...`; |
| timingFeed.innerHTML = `<i class="fa-solid fa-satellite fa-spin"></i> Aligning sensor domains...`; |
|
|
| const formData = new FormData(); |
| const level = document.getElementById("retrieval-level").value; |
| const k = document.getElementById("k-input").value; |
| const modality = document.getElementById("query-modality").value; |
|
|
| let url = "/api/search"; |
| |
| formData.append("k", k); |
| formData.append("level", level); |
| formData.append("query_modality", modality); |
|
|
| if (level === "level4") { |
| const lat = document.getElementById("lat-input").value; |
| const lon = document.getElementById("lon-input").value; |
| const radius = document.getElementById("radius-input").value; |
| formData.append("lat", lat); |
| formData.append("lon", lon); |
| formData.append("radius_km", radius); |
| } |
|
|
| if (activeSearchMode === "image") { |
| formData.append("file", uploadedFile); |
| } else { |
| url = "/api/search-text"; |
| formData.append("text_query", document.getElementById("text-query-input").value); |
| } |
|
|
| fetch(url, { |
| method: "POST", |
| body: formData |
| }) |
| .then(response => { |
| if (!response.ok) { |
| throw new Error("Server error occurred during retrieval."); |
| } |
| return response.json(); |
| }) |
| .then(data => { |
| renderResults(data); |
| }) |
| .catch(err => { |
| console.error(err); |
| alert(`Search failed: ${err.message}`); |
| timingFeed.innerHTML = `<i class="fa-solid fa-triangle-exclamation" style="color:var(--error)"></i> Error in search`; |
| }) |
| .finally(() => { |
| searchBtn.disabled = false; |
| searchBtn.innerHTML = `<i class="fa-solid fa-circle-play"></i> RUN ALIGNMENT & SEARCH`; |
| }); |
| }); |
|
|
| |
| |
| |
| function renderResults(data) { |
| const results = data.results; |
| const timeMs = data.query_time_ms.toFixed(0); |
| const device = data.device || "cpu"; |
|
|
| |
| document.getElementById("telemetry-device").textContent = device.toUpperCase(); |
| timingFeed.innerHTML = `<i class="fa-solid fa-bolt"></i> Completed in ${timeMs}ms`; |
|
|
| |
| resultsMarkersGroup.clearLayers(); |
| h3GridGroup.clearLayers(); |
|
|
| if (results.length === 0) { |
| resultsEmpty.style.display = "flex"; |
| resultsGrid.style.display = "none"; |
| resultsTableContainer.style.display = "none"; |
| return; |
| } |
|
|
| resultsEmpty.style.display = "none"; |
| resultsGrid.style.display = "grid"; |
| resultsTableContainer.style.display = "block"; |
|
|
| resultsGrid.innerHTML = ""; |
| resultsTableBody.innerHTML = ""; |
|
|
| const mapBounds = L.latLngBounds(); |
|
|
| results.forEach((item, index) => { |
| const rank = index + 1; |
| const score = item.score.toFixed(4); |
| const lat = item.lat ? item.lat.toFixed(5) : "N/A"; |
| const lon = item.lon ? item.lon.toFixed(5) : "N/A"; |
| const dist = item.distance_km ? `${item.distance_km.toFixed(1)} km` : "N/A"; |
| const h3Cell = item.h3_cell || "N/A"; |
|
|
| |
| const card = document.createElement("div"); |
| card.className = "result-card card"; |
| |
| |
| const isMs = item.modality === "multispectral"; |
| const actionHTML = isMs ? ` |
| <div class="result-actions"> |
| <button class="action-btn toggle-fcc-btn" data-path="${item.original_path}" data-active="rgb" title="Toggle NIR False Color Composite (FCC)"> |
| <i class="fa-solid fa-wand-magic-sparkles"></i> FCC |
| </button> |
| <button class="action-btn plot-spectral-btn" data-path="${item.original_path}" title="Plot Spectral Signature"> |
| <i class="fa-solid fa-chart-line"></i> |
| </button> |
| </div> |
| ` : ''; |
|
|
| card.innerHTML = ` |
| <div class="result-img-wrapper"> |
| <img src="${item.gallery_path}" alt="${item.class}" id="img-result-${index}"> |
| <span class="result-score-badge">S: ${score}</span> |
| <span class="result-modality-tag">${item.modality}</span> |
| ${actionHTML} |
| </div> |
| <div class="result-content"> |
| <div class="result-meta-title"> |
| <h4>${item.class}</h4> |
| <span class="result-meta-rank">#0${rank}</span> |
| </div> |
| <div class="result-details"> |
| <span><strong>Lat:</strong> ${lat}</span> |
| <span><strong>Lon:</strong> ${lon}</span> |
| <span><strong>Dist:</strong> ${dist}</span> |
| <span><strong>H3:</strong> ${h3Cell}</span> |
| </div> |
| </div> |
| `; |
| resultsGrid.appendChild(card); |
|
|
| |
| if (isMs) { |
| const btn = card.querySelector(".toggle-fcc-btn"); |
| btn.addEventListener("click", (e) => { |
| e.stopPropagation(); |
| const activeMode = btn.getAttribute("data-active"); |
| const path = btn.getAttribute("data-path"); |
| const imgEl = document.getElementById(`img-result-${index}`); |
| |
| if (activeMode === "rgb") { |
| btn.setAttribute("data-active", "fcc"); |
| btn.innerHTML = `<i class="fa-solid fa-image"></i> RGB`; |
| imgEl.src = `/api/render-bands?path=${encodeURIComponent(path)}&bands=FCC`; |
| } else { |
| btn.setAttribute("data-active", "rgb"); |
| btn.innerHTML = `<i class="fa-solid fa-wand-magic-sparkles"></i> FCC`; |
| imgEl.src = `/api/render-bands?path=${encodeURIComponent(path)}&bands=RGB`; |
| } |
| }); |
|
|
| |
| const spectralBtn = card.querySelector(".plot-spectral-btn"); |
| spectralBtn.addEventListener("click", () => { |
| openSpectralModal(item.original_path, item.class); |
| }); |
| } |
|
|
| |
| const row = document.createElement("tr"); |
| row.innerHTML = ` |
| <td><strong>0${rank}</strong></td> |
| <td><img src="${item.gallery_path}" class="table-thumbnail"></td> |
| <td><strong>${item.class}</strong></td> |
| <td><span class="badge">${item.modality.toUpperCase()}</span></td> |
| <td><code style="font-family:var(--font-mono)">${h3Cell}</code></td> |
| <td><code>${lat}, ${lon}</code></td> |
| <td>${dist}</td> |
| <td class="table-score">${score}</td> |
| `; |
| resultsTableBody.appendChild(row); |
|
|
| |
| if (item.lat && item.lon) { |
| const pCoords = [item.lat, item.lon]; |
| const marker = L.marker(pCoords).addTo(resultsMarkersGroup); |
| |
| |
| marker.bindPopup(` |
| <div style="width:140px; text-align:center;"> |
| <img src="${item.gallery_path}" style="width:100%; border-radius:4px; margin-bottom:0.375rem;"> |
| <strong>Rank #${rank} • ${item.class}</strong><br> |
| Modality: ${item.modality}<br> |
| Score: ${score}<br> |
| Dist: ${dist} |
| </div> |
| `); |
|
|
| mapBounds.extend(pCoords); |
|
|
| |
| if (item.h3_boundary) { |
| L.polygon(item.h3_boundary, { |
| color: "#10b981", |
| fillColor: "#10b981", |
| fillOpacity: 0.15, |
| weight: 1 |
| }).addTo(h3GridGroup); |
| } |
| } |
| }); |
|
|
| |
| if (map && results.some(item => item.lat && item.lon)) { |
| map.fitBounds(mapBounds, { padding: [50, 50] }); |
| } |
| } |
|
|
| |
| |
| |
| const modal = document.getElementById("spectral-modal"); |
| const closeModalBtn = document.getElementById("close-modal-btn"); |
| let spectralChartInstance = null; |
|
|
| closeModalBtn.addEventListener("click", () => { |
| modal.classList.remove("active"); |
| }); |
|
|
| function openSpectralModal(path, className) { |
| modal.classList.add("active"); |
| document.getElementById("modal-title").textContent = `Sentinel-2 Spectral Signature - ${className}`; |
|
|
| fetch(`/api/spectral-signature?path=${encodeURIComponent(path)}`) |
| .then(res => res.json()) |
| .then(data => { |
| renderSpectralChart(data.reflectance); |
| }) |
| .catch(err => { |
| console.error(err); |
| alert("Failed to load spectral bands."); |
| }); |
| } |
|
|
| function renderSpectralChart(values) { |
| const ctx = document.getElementById("spectral-chart").getContext("2d"); |
| const bands = ["B01 (Aer)", "B02 (B)", "B03 (G)", "B04 (R)", "B05 (RE1)", "B06 (RE2)", "B07 (RE3)", "B08 (NIR)", "B08A (N2)", "B09 (WV)", "B10 (Cir)", "B11 (SW1)", "B12 (SW2)"]; |
| |
| if (spectralChartInstance) { |
| spectralChartInstance.destroy(); |
| } |
|
|
| spectralChartInstance = new Chart(ctx, { |
| type: "line", |
| data: { |
| labels: bands, |
| datasets: [{ |
| label: "Reflectance Index", |
| data: values, |
| borderColor: "#2563eb", |
| backgroundColor: "rgba(37, 99, 235, 0.1)", |
| borderWidth: 2, |
| fill: true, |
| tension: 0.3 |
| }] |
| }, |
| options: { |
| responsive: true, |
| maintainAspectRatio: false, |
| scales: { |
| y: { |
| beginAtZero: true, |
| title: { display: true, text: "Scaled Reflectance Value" } |
| } |
| } |
| } |
| }); |
| } |
|
|
| |
| |
| |
| let benchmarksLoaded = false; |
| let recallChartInstance = null; |
| let latencyChartInstance = null; |
|
|
| function loadBenchmarks() { |
| if (benchmarksLoaded) return; |
|
|
| fetch("/api/benchmarks") |
| .then(res => res.json()) |
| .then(data => { |
| renderBenchmarksGrid(data); |
| benchmarksLoaded = true; |
| }) |
| .catch(err => { |
| console.error("Failed to load benchmarks", err); |
| }); |
| } |
|
|
| function renderBenchmarksGrid(results) { |
| |
| const tbody = document.getElementById("benchmarks-table-body"); |
| tbody.innerHTML = ""; |
|
|
| results.forEach(r => { |
| const tr = document.createElement("tr"); |
| if (r.model.includes("Proposed")) { |
| tr.style.backgroundColor = "rgba(16, 185, 129, 0.05)"; |
| tr.style.borderLeft = "4px solid var(--success)"; |
| } else if (r.model.includes("Spectral Calibration")) { |
| tr.style.backgroundColor = "rgba(37, 99, 235, 0.04)"; |
| tr.style.borderLeft = "4px solid var(--primary-color)"; |
| } |
| tr.innerHTML = ` |
| <td style="padding: 10px 8px;"><strong>${r.model}</strong></td> |
| <td style="padding: 10px 8px; text-align: center; font-family: var(--font-mono);">${r.same_r1.toFixed(3)}</td> |
| <td style="padding: 10px 8px; text-align: center; font-family: var(--font-mono); font-weight: 700; color: var(--primary-color);">${r.same_r5.toFixed(3)}</td> |
| <td style="padding: 10px 8px; text-align: center; font-family: var(--font-mono);">${r.same_r10.toFixed(3)}</td> |
| <td style="padding: 10px 8px; text-align: center; font-family: var(--font-mono);">${r.cross_r1.toFixed(3)}</td> |
| <td style="padding: 10px 8px; text-align: center; font-family: var(--font-mono); font-weight: 700; color: var(--success);">${r.cross_r5.toFixed(3)}</td> |
| <td style="padding: 10px 8px; text-align: center; font-family: var(--font-mono);">${r.cross_r10.toFixed(3)}</td> |
| <td style="padding: 10px 8px; text-align: center;"><code style="background: var(--bg-main); padding: 2px 6px; border-radius: 4px; font-weight: 600; color: #f59e0b;">${r.latency_ms.toFixed(0)} ms</code></td> |
| `; |
| tbody.appendChild(tr); |
| }); |
|
|
| |
| const ctxRecall = document.getElementById("recall-chart").getContext("2d"); |
| const labels = results.map(r => r.model); |
| const sameR5 = results.map(r => r.same_r5); |
| const crossR5 = results.map(r => r.cross_r5); |
|
|
| if (recallChartInstance) recallChartInstance.destroy(); |
| recallChartInstance = new Chart(ctxRecall, { |
| type: "bar", |
| data: { |
| labels: labels, |
| datasets: [ |
| { |
| label: "Same-Modal Recall@5", |
| data: sameR5, |
| backgroundColor: "rgba(37, 99, 235, 0.7)", |
| borderColor: "#2563eb", |
| borderWidth: 1 |
| }, |
| { |
| label: "Cross-Modal Recall@5", |
| data: crossR5, |
| backgroundColor: "rgba(16, 185, 129, 0.7)", |
| borderColor: "#10b981", |
| borderWidth: 1 |
| } |
| ] |
| }, |
| options: { |
| responsive: true, |
| maintainAspectRatio: false, |
| scales: { |
| y: { |
| beginAtZero: true, |
| max: 0.6, |
| title: { display: true, text: "Score" } |
| } |
| } |
| } |
| }); |
|
|
| |
| const ctxLatency = document.getElementById("latency-chart").getContext("2d"); |
| const latencies = results.map(r => r.latency_ms); |
|
|
| if (latencyChartInstance) latencyChartInstance.destroy(); |
| latencyChartInstance = new Chart(ctxLatency, { |
| type: "bar", |
| data: { |
| labels: labels, |
| datasets: [{ |
| label: "Average Search Latency (ms)", |
| data: latencies, |
| backgroundColor: "rgba(245, 158, 11, 0.7)", |
| borderColor: "#f59e0b", |
| borderWidth: 1 |
| }] |
| }, |
| options: { |
| responsive: true, |
| maintainAspectRatio: false, |
| scales: { |
| y: { |
| beginAtZero: true, |
| title: { display: true, text: "Latency (ms)" } |
| } |
| } |
| } |
| }); |
| } |
|
|
| |
| |
| |
| document.querySelectorAll(".sample-query-tile").forEach(tile => { |
| tile.addEventListener("click", async () => { |
| const path = tile.getAttribute("data-path"); |
| const name = tile.getAttribute("data-name"); |
| const type = tile.getAttribute("data-type"); |
|
|
| |
| tile.style.borderColor = "var(--primary-color)"; |
|
|
| try { |
| |
| const res = await fetch(path); |
| const blob = await res.blob(); |
| const file = new File([blob], name, { type: blob.type || "image/png" }); |
|
|
| |
| document.getElementById("mode-image-btn").click(); |
|
|
| |
| document.getElementById("query-modality").value = type; |
|
|
| |
| handleFile(file); |
|
|
| |
| searchBtn.click(); |
| } catch (err) { |
| console.error("Failed to load sample query file:", err); |
| alert("Failed to load sample query file: " + err.message); |
| } finally { |
| setTimeout(() => { |
| tile.style.borderColor = "#ced4da"; |
| }, 1000); |
| } |
| }); |
| }); |
|
|
| |
| |
| |
| const bannerMsgs = document.querySelectorAll(".banner-msg"); |
| if (bannerMsgs.length > 0) { |
| let currentMsgIndex = 0; |
| setInterval(() => { |
| bannerMsgs[currentMsgIndex].classList.remove("active"); |
| currentMsgIndex = (currentMsgIndex + 1) % bannerMsgs.length; |
| bannerMsgs[currentMsgIndex].classList.add("active"); |
| }, 5000); |
| } |
|
|
| |
| |
| |
| const members = ["ayush", "karan", "anurag"]; |
| members.forEach(member => { |
| const linkEl = document.getElementById(`${member}-linkedin-link`); |
| const editEl = document.getElementById(`${member}-edit-linkedin`); |
| const inputEl = document.getElementById(`${member}-linkedin-input`); |
| |
| function showLink(url) { |
| linkEl.href = url; |
| linkEl.style.display = "inline-block"; |
| editEl.style.display = "inline-block"; |
| inputEl.style.display = "none"; |
| } |
| |
| function showInput() { |
| linkEl.style.display = "none"; |
| editEl.style.display = "none"; |
| inputEl.style.display = "inline-block"; |
| inputEl.value = localStorage.getItem(`${member}_linkedin_url`) || ""; |
| } |
|
|
| const savedUrl = localStorage.getItem(`${member}_linkedin_url`); |
| if (savedUrl) { |
| showLink(savedUrl); |
| } else { |
| showInput(); |
| } |
|
|
| inputEl.addEventListener("change", (e) => { |
| let url = e.target.value.trim(); |
| if (url) { |
| if (!url.startsWith("http://") && !url.startsWith("https://")) { |
| url = "https://" + url; |
| } |
| localStorage.setItem(`${member}_linkedin_url`, url); |
| showLink(url); |
| } |
| }); |
|
|
| editEl.addEventListener("click", (e) => { |
| e.preventDefault(); |
| showInput(); |
| }); |
| }); |
|
|
| |
| |
| |
| const simWeight = document.getElementById("sim-modality-weight"); |
| const simNoise = document.getElementById("sim-noise-level"); |
| const simH3Res = document.getElementById("sim-h3-resolution"); |
|
|
| function updateSimulation() { |
| if (!simWeight) return; |
| const w = parseFloat(simWeight.value); |
| const n = parseFloat(simNoise.value); |
| const res = parseInt(simH3Res.value); |
|
|
| document.getElementById("sim-weight-val").innerText = w.toFixed(2); |
| document.getElementById("sim-noise-val").innerText = n.toFixed(2); |
|
|
| |
| const baseR1 = 0.45 + 0.12 * Math.sin(w * Math.PI) - 0.3 * n; |
| const r1 = Math.max(0.1, Math.min(0.99, baseR1)); |
| const r5 = Math.max(r1 + 0.05, Math.min(0.99, r1 * 1.15 + 0.05)); |
| const mapVal = Math.max(r5 + 0.05, Math.min(0.99, r5 * 1.12 + 0.04)); |
|
|
| |
| const latency = Math.round(28 + (8 - res) * 4 + w * 2 + n * 2); |
|
|
| document.getElementById("sim-metric-r1").innerText = (r1 * 100).toFixed(1) + "%"; |
| document.getElementById("sim-metric-r5").innerText = (r5 * 100).toFixed(1) + "%"; |
| document.getElementById("sim-metric-map").innerText = (mapVal * 100).toFixed(1) + "%"; |
| document.getElementById("sim-metric-latency").innerText = latency + " ms"; |
| } |
|
|
| if (simWeight) { |
| simWeight.addEventListener("input", updateSimulation); |
| simNoise.addEventListener("input", updateSimulation); |
| simH3Res.addEventListener("change", updateSimulation); |
| updateSimulation(); |
| } |
|
|
| }); |
|
|