Add vector change detection foundation
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
import type { ChangeDetectionSummary, DatasetCreateResponse } from '../../types'
|
||||
|
||||
interface ChangeDetectionPanelProps {
|
||||
vectorDatasets: DatasetCreateResponse[]
|
||||
sourceDatasetId: string
|
||||
targetDatasetId: string
|
||||
iouThreshold: number
|
||||
includeUnchanged: boolean
|
||||
running: boolean
|
||||
result: ChangeDetectionSummary | null
|
||||
error: string | null
|
||||
onSourceDatasetChange: (value: string) => void
|
||||
onTargetDatasetChange: (value: string) => void
|
||||
onIouThresholdChange: (value: number) => void
|
||||
onIncludeUnchangedChange: (value: boolean) => void
|
||||
onRun: () => void
|
||||
}
|
||||
|
||||
function datasetLabel(dataset: DatasetCreateResponse): string {
|
||||
const role = dataset.dataset_role ? ` (${dataset.dataset_role})` : ''
|
||||
return `${dataset.name}${role}`
|
||||
}
|
||||
|
||||
export function ChangeDetectionPanel({
|
||||
vectorDatasets,
|
||||
sourceDatasetId,
|
||||
targetDatasetId,
|
||||
iouThreshold,
|
||||
includeUnchanged,
|
||||
running,
|
||||
result,
|
||||
error,
|
||||
onSourceDatasetChange,
|
||||
onTargetDatasetChange,
|
||||
onIouThresholdChange,
|
||||
onIncludeUnchangedChange,
|
||||
onRun,
|
||||
}: ChangeDetectionPanelProps): JSX.Element {
|
||||
return (
|
||||
<section className="panel">
|
||||
<div className="panel-header">
|
||||
<div>
|
||||
<p className="eyebrow">Analysis</p>
|
||||
<h2>Change Detection</h2>
|
||||
</div>
|
||||
<button disabled={running || vectorDatasets.length < 2} onClick={onRun} type="button">
|
||||
{running ? 'Comparing...' : 'Compare vectors'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="form-grid">
|
||||
<label>
|
||||
Source vector
|
||||
<select value={sourceDatasetId} onChange={(event) => onSourceDatasetChange(event.target.value)}>
|
||||
<option value="">Select source</option>
|
||||
{vectorDatasets.map((dataset) => (
|
||||
<option key={dataset.id} value={dataset.id}>
|
||||
{datasetLabel(dataset)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Target vector
|
||||
<select value={targetDatasetId} onChange={(event) => onTargetDatasetChange(event.target.value)}>
|
||||
<option value="">Select target</option>
|
||||
{vectorDatasets.map((dataset) => (
|
||||
<option key={dataset.id} value={dataset.id}>
|
||||
{datasetLabel(dataset)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
IoU threshold
|
||||
<input
|
||||
max="1"
|
||||
min="0"
|
||||
step="0.05"
|
||||
type="number"
|
||||
value={iouThreshold}
|
||||
onChange={(event) => onIouThresholdChange(Number(event.target.value))}
|
||||
/>
|
||||
</label>
|
||||
<label className="checkbox-row">
|
||||
<input
|
||||
checked={includeUnchanged}
|
||||
type="checkbox"
|
||||
onChange={(event) => onIncludeUnchangedChange(event.target.checked)}
|
||||
/>
|
||||
Include unchanged geometry
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{error ? <p className="error">{error}</p> : null}
|
||||
{!error && vectorDatasets.length < 2 ? <p className="muted">Upload at least two vector datasets to compare.</p> : null}
|
||||
|
||||
{result ? (
|
||||
<div className="summary-grid">
|
||||
<div>
|
||||
<span className="metric">{result.added_count}</span>
|
||||
<span>Added</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="metric">{result.removed_count}</span>
|
||||
<span>Removed</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="metric">{result.unchanged_count}</span>
|
||||
<span>Unchanged</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="metric">{result.geojson.features.length}</span>
|
||||
<span>Map features</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{result?.warnings.length ? (
|
||||
<ul className="compact-list">
|
||||
{result.warnings.map((warning) => (
|
||||
<li key={warning}>{warning}</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user