Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>DDA Change Detection</title> | |
| <link rel="stylesheet" href="/static/css/style.css?v=30" /> | |
| <link rel="stylesheet" href="/static/css/dda.css?v=13" /> | |
| </head> | |
| <body> | |
| <div class="app dda-app"> | |
| <header class="dda-header"> | |
| <div class="app-brand"> | |
| <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></svg> | |
| <span>DDA Change Detection</span> | |
| <span class="dda-badge">Dev</span> | |
| </div> | |
| <nav class="dda-tabs" role="tablist"> | |
| <button type="button" class="dda-tab active" data-tab="library" role="tab">Image Library</button> | |
| <button type="button" class="dda-tab" data-tab="detect" role="tab">Change Detection</button> | |
| <button type="button" class="dda-tab" data-tab="reports" role="tab">Reports</button> | |
| </nav> | |
| <div class="dda-notify-wrap"> | |
| <button type="button" id="dda-notify-btn" class="dda-notify-btn" title="Job notifications" aria-label="Notifications"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg> | |
| <span id="dda-notify-badge" class="dda-notify-badge hidden">0</span> | |
| </button> | |
| <div id="dda-notify-panel" class="dda-notify-panel hidden" role="menu"></div> | |
| </div> | |
| </header> | |
| <div id="dda-error" class="alert alert-error hidden"></div> | |
| <div id="dda-success" class="alert alert-success hidden"></div> | |
| <!-- Tab: Image Library — unlimited-depth tree --> | |
| <section id="tab-library" class="dda-panel active" role="tabpanel"> | |
| <div class="dda-layout"> | |
| <aside class="dda-sidebar card"> | |
| <div class="card-header"> | |
| <h3>Library tree</h3> | |
| <div class="dda-sidebar-actions"> | |
| <button type="button" class="btn btn-secondary btn-sm hidden" id="btn-manage-library">Manage</button> | |
| <button type="button" class="btn btn-secondary btn-sm" id="btn-refresh-lib">Refresh</button> | |
| </div> | |
| </div> | |
| <div id="lib-folder-path" class="dda-folder-path dim"></div> | |
| <input type="search" id="lib-tree-search" class="dda-search" placeholder="Filter nodes…" /> | |
| <div id="lib-tree" class="dda-tree"><p class="dim">Loading…</p></div> | |
| </aside> | |
| <main class="dda-main"> | |
| <div class="card dda-instructions"> | |
| <div class="card-header"> | |
| <h3>Tree library</h3> | |
| <span class="dim" id="lib-config-hint"></span> | |
| </div> | |
| <p class="sub" id="lib-instructions">Organize images in a configurable zone → area → year → type hierarchy.</p> | |
| <pre id="lib-path-display" class="dda-path-code"></pre> | |
| </div> | |
| <div class="card" id="upload-card"> | |
| <div class="card-header"> | |
| <h3>Upload image</h3> | |
| </div> | |
| <p class="sub" id="upload-limit-hint">Select a tree node and image type.</p> | |
| <form id="form-tree-upload" class="dda-upload-form"> | |
| <div class="location-row"> | |
| <div class="form-group"> | |
| <label for="upload-node">Tree node</label> | |
| <select id="upload-node" required><option value="">— Select node —</option></select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="upload-image-type">Image type</label> | |
| <select id="upload-image-type"> | |
| <option>GeoTIFF</option><option>Satellite</option><option>Drone</option> | |
| <option>Orthomosaic</option><option>DEM</option><option>Raster</option> | |
| <option>PNG</option><option>JPEG</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="upload-capture-date">Capture date</label> | |
| <input type="date" id="upload-capture-date" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="upload-file">File</label> | |
| <input type="file" id="upload-file" accept=".tif,.tiff,.png,.jpg,.jpeg" required /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="upload-manual-bounds">Geo bounds (W,S,E,N)</label> | |
| <input type="text" id="upload-manual-bounds" placeholder="optional, e.g. 77.5,12.9,77.6,13.0" /> | |
| </div> | |
| </div> | |
| <div id="upload-progress" class="dda-upload-progress hidden"> | |
| <div class="dda-progress-bar"><div id="upload-progress-fill" class="dda-progress-fill"></div></div> | |
| <span id="upload-progress-label" class="dim">Uploading…</span> | |
| </div> | |
| <button type="submit" class="btn btn-primary" id="btn-tree-upload">Upload to node</button> | |
| </form> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h3 id="lib-grid-title">Images</h3> | |
| <input type="search" id="lib-filter" class="dda-search" placeholder="Search filenames…" /> | |
| </div> | |
| <div id="lib-grid" class="dda-grid"><p class="dim">Select a node in the tree.</p></div> | |
| </div> | |
| </main> | |
| </div> | |
| </section> | |
| <!-- Tab: Change Detection --> | |
| <section id="tab-detect" class="dda-panel" role="tabpanel"> | |
| <div class="dda-layout"> | |
| <aside class="dda-sidebar card"> | |
| <div class="card-header"> | |
| <h3>Folders</h3> | |
| <button type="button" class="btn btn-secondary btn-sm" id="btn-compare-refresh">Refresh</button> | |
| </div> | |
| <div id="compare-folder-path" class="dda-folder-path dim">All images</div> | |
| <input type="search" id="compare-tree-search" class="dda-search" placeholder="Filter nodes…" /> | |
| <div id="compare-tree" class="dda-tree"><p class="dim">Loading…</p></div> | |
| </aside> | |
| <main class="dda-main"> | |
| <div class="card"> | |
| <div class="card-header"><h3>Compare Images</h3></div> | |
| <p class="sub">Select <strong>Old Image (T1)</strong> and <strong>New Image (T2)</strong> from the library, then run detection.</p> | |
| <div class="dda-compare-slots"> | |
| <div class="dda-slot" id="slot-t1" data-slot="t1"> | |
| <span class="dda-slot-label">Old Image (T1)</span> | |
| <div id="slot-t1-preview" class="dda-slot-preview-wrap"></div> | |
| <select id="select-t1" class="dda-image-select" aria-label="Select old image"> | |
| <option value="">— Choose old image —</option> | |
| </select> | |
| <button type="button" class="btn btn-secondary btn-sm dda-slot-pick" data-pick="t1">Browse library</button> | |
| </div> | |
| <div class="dda-slot" id="slot-t2" data-slot="t2"> | |
| <span class="dda-slot-label">New Image (T2)</span> | |
| <div id="slot-t2-preview" class="dda-slot-preview-wrap"></div> | |
| <select id="select-t2" class="dda-image-select" aria-label="Select new image"> | |
| <option value="">— Choose new image —</option> | |
| </select> | |
| <button type="button" class="btn btn-secondary btn-sm dda-slot-pick" data-pick="t2">Browse library</button> | |
| </div> | |
| </div> | |
| <div class="dda-compare-library card"> | |
| <div class="card-header"> | |
| <h3 id="compare-grid-title">Pick from library</h3> | |
| </div> | |
| <p class="sub dim">Click <strong>T1</strong> or <strong>T2</strong> on an image, or use the dropdowns above (all images).</p> | |
| <div id="compare-lib-grid" class="dda-grid dda-compare-grid"> | |
| <p class="dim">Loading library images…</p> | |
| </div> | |
| </div> | |
| <div class="dda-detect-options"> | |
| <div class="form-group"> | |
| <label for="dda-detect-method">Method</label> | |
| <select id="dda-detect-method"> | |
| <option value="AI-Based Deep Learning">AI-Based Deep Learning</option> | |
| <option value="Hybrid AI">Hybrid AI</option> | |
| <option value="Hybrid Approach">Hybrid Approach</option> | |
| <option value="Image Difference">Image Difference</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="dda-detect-sensitivity">Sensitivity (0–1)</label> | |
| <input type="number" id="dda-detect-sensitivity" min="0" max="1" step="0.05" value="0.45" /> | |
| </div> | |
| <div class="form-group"> | |
| <label for="dda-detect-min-area">Min region area (px)</label> | |
| <input type="number" id="dda-detect-min-area" min="50" max="10000" step="10" value="150" /> | |
| </div> | |
| <label class="dda-check"><input type="checkbox" id="dda-detect-registration" checked /> Image registration</label> | |
| <label class="dda-check"><input type="checkbox" id="dda-detect-normalization" checked /> Normalization</label> | |
| <label class="dda-check"><input type="checkbox" id="dda-detect-notify" /> Email report when done</label> | |
| <input type="email" id="dda-detect-notify-email" class="dda-notify-email hidden" placeholder="recipient@example.com" /> | |
| </div> | |
| <p class="dim" id="dda-detect-res-hint"></p> | |
| <button type="button" class="btn btn-primary" id="btn-run-job" disabled>Run Detection</button> | |
| <div id="detect-progress" class="dda-upload-progress hidden" style="margin-top:0.75rem"> | |
| <div class="dda-progress-bar"><div id="detect-progress-fill" class="dda-progress-fill"></div></div> | |
| <span id="detect-progress-label" class="dim">Starting detection…</span> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| </section> | |
| <!-- Tab: Reports (FR-05) --> | |
| <section id="tab-reports" class="dda-panel" role="tabpanel"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <h3>Detection Reports</h3> | |
| <button type="button" class="btn btn-secondary btn-sm" id="btn-reports-refresh">Refresh</button> | |
| </div> | |
| <p class="sub dim">Completed jobs and detection history. Download PDF or open the browser report.</p> | |
| <div id="reports-list"><p class="dim">Open this tab to load reports.</p></div> | |
| </div> | |
| </section> | |
| </div> | |
| <div id="dda-picker-modal" class="dda-modal hidden" role="dialog" aria-modal="true"> | |
| <div class="dda-modal-panel card"> | |
| <div class="card-header"> | |
| <h3 id="dda-picker-title">Select image</h3> | |
| <button type="button" class="btn btn-secondary btn-sm" id="dda-picker-close">Close</button> | |
| </div> | |
| <div id="dda-picker-list" class="dda-picker-grid"></div> | |
| </div> | |
| </div> | |
| <!-- Result modal — same before/changes slider as production --> | |
| <div class="result-modal-backdrop hidden" id="result-modal"> | |
| <div class="result-modal"> | |
| <div class="result-modal-header"> | |
| <h3 id="result-modal-title">Detection Result</h3> | |
| <button type="button" class="btn-close-modal" id="result-modal-close" aria-label="Close"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> | |
| </button> | |
| </div> | |
| <div class="result-stats" id="result-stats"></div> | |
| <div class="dda-view-toolbar"> | |
| <span class="dda-view-label">View:</span> | |
| <button type="button" class="dda-view-btn active" data-view="slider">Slider</button> | |
| <button type="button" class="dda-view-btn" data-view="t1">Old Image (T1)</button> | |
| <button type="button" class="dda-view-btn" data-view="t2">New Image (T2)</button> | |
| <button type="button" class="dda-view-btn" data-view="overlay">Overlay</button> | |
| <button type="button" class="btn btn-secondary btn-sm" id="dda-locate-btn" title="Locate selected region" disabled>Locate</button> | |
| </div> | |
| <div class="zoom-slider-section"> | |
| <div class="zoom-controls"> | |
| <button type="button" class="btn btn-zoom" id="zoom-out" title="Zoom out" aria-label="Zoom out">−</button> | |
| <span class="zoom-level" id="zoom-level">100%</span> | |
| <button type="button" class="btn btn-zoom" id="zoom-in" title="Zoom in" aria-label="Zoom in">+</button> | |
| </div> | |
| <div class="zoom-wrapper" id="zoom-wrapper"> | |
| <div class="compare-slider compare-slider-zoomed" id="compare-slider"> | |
| <div class="compare-before"> | |
| <img id="compare-before-img" alt="Before" draggable="false" /> | |
| <span class="compare-label compare-label-left">Before</span> | |
| </div> | |
| <div class="compare-after" id="compare-after-clip"> | |
| <img id="compare-after-img" alt="Changes detected" draggable="false" /> | |
| <span class="compare-label compare-label-right">Changes</span> | |
| </div> | |
| <div class="compare-handle" id="compare-handle"> | |
| <div class="compare-handle-line"></div> | |
| <div class="compare-handle-knob"> | |
| <svg width="20" height="20" viewBox="0 0 20 20"><path d="M6 10l4-5v10z" fill="currentColor"/><path d="M14 10l-4-5v10z" fill="currentColor"/></svg> | |
| </div> | |
| <div class="compare-handle-line"></div> | |
| </div> | |
| <div class="region-highlight-overlay" id="region-highlight-overlay"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="dda-review-bar" id="dda-review-bar"> | |
| <span class="dda-review-summary dim" id="dda-review-summary"></span> | |
| <div class="dda-review-actions"> | |
| <a class="btn btn-secondary btn-sm" id="dda-export-csv" href="#" download>Export CSV</a> | |
| <a class="btn btn-secondary btn-sm" id="dda-export-confirmed" href="#" download>Export confirmed</a> | |
| <button type="button" class="btn btn-primary btn-sm" id="dda-submit-dept">Submit confirmed</button> | |
| </div> | |
| </div> | |
| <div class="regions-table-wrap"> | |
| <table class="regions-table" id="regions-table"> | |
| <thead> | |
| <tr> | |
| <th>#</th> | |
| <th>Change Type</th> | |
| <th>DDA Type</th> | |
| <th>Lat/Lng</th> | |
| <th>Sub-Type</th> | |
| <th>Severity</th> | |
| <th>Confidence</th> | |
| <th>Area (px)</th> | |
| <th>Coordinates</th> | |
| <th>Stories</th> | |
| <th>Height</th> | |
| <th>Stage</th> | |
| <th>Review</th> | |
| <th>Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="regions-tbody"></tbody> | |
| </table> | |
| <div class="pagination" id="regions-pagination"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="dda-manage-modal" class="dda-modal hidden" role="dialog"> | |
| <div class="dda-modal-panel card dda-manage-panel"> | |
| <div class="card-header"> | |
| <h3>Manage tree</h3> | |
| <button type="button" class="btn btn-secondary btn-sm" id="dda-manage-close">Close</button> | |
| </div> | |
| <div class="dda-manage-section"> | |
| <h4>Add node</h4> | |
| <div class="location-row"> | |
| <select id="add-child-parent"><option value="">— Root —</option></select> | |
| <input type="text" id="add-node-name" placeholder="Node name" /> | |
| <select id="add-node-type"> | |
| <option>Zone</option><option>Area</option><option>Year</option> | |
| <option>Satellite Images</option><option>Drone Survey</option><option>Change Detection</option> | |
| <option>Folder</option> | |
| </select> | |
| <button type="button" class="btn btn-primary btn-sm" id="btn-add-node">Add</button> | |
| </div> | |
| </div> | |
| <div class="dda-manage-section"> | |
| <h4>Edit / move / delete</h4> | |
| <select id="manage-node-select"></select> | |
| <div class="location-row"> | |
| <input type="text" id="rename-node-name" placeholder="Rename to…" /> | |
| <button type="button" class="btn btn-secondary btn-sm" id="btn-rename-node">Rename</button> | |
| </div> | |
| <div class="location-row"> | |
| <select id="move-parent"><option value="">— Move to root —</option></select> | |
| <button type="button" class="btn btn-secondary btn-sm" id="btn-move-node">Move</button> | |
| </div> | |
| <label class="dda-check"><input type="checkbox" id="delete-files-check" /> Delete files on disk</label> | |
| <button type="button" class="btn btn-secondary btn-sm" id="btn-delete-node">Delete node</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="/static/js/dda/app.js?v=15"></script> | |
| <script src="/static/js/dda/tree.js?v=2"></script> | |
| <script src="/static/js/dda/library.js?v=10"></script> | |
| <script src="/static/js/dda/result.js?v=7"></script> | |
| <script src="/static/js/dda/compare.js?v=14"></script> | |
| <script src="/static/js/dda/reports.js?v=4"></script> | |
| <script src="/static/js/dda/notifications.js?v=1"></script> | |
| </body> | |
| </html> | |