Add V1 selected area map overlay
This commit is contained in:
+81
-2
@@ -96,6 +96,9 @@ function App(): JSX.Element {
|
||||
const [datasetContent, setDatasetContent] = useState<GeoJSON.FeatureCollection | null>(null)
|
||||
const [mapLayerVisible, setMapLayerVisible] = useState(true)
|
||||
const [mapLayerOpacity, setMapLayerOpacity] = useState(0.4)
|
||||
const [selectedMapAreaId, setSelectedMapAreaId] = useState('')
|
||||
const [areaLayerVisible, setAreaLayerVisible] = useState(true)
|
||||
const [areaLayerOpacity, setAreaLayerOpacity] = useState(0.18)
|
||||
const [selectedMapFeature, setSelectedMapFeature] = useState<GeoJSON.Feature | null>(null)
|
||||
const [jobs, setJobs] = useState<JobRead[]>([])
|
||||
const [providerCapabilities, setProviderCapabilities] = useState<ProviderCapability[]>([])
|
||||
@@ -243,6 +246,31 @@ function App(): JSX.Element {
|
||||
() => segmentationModels.find((model) => model.model_id === selectedSegmentationModelId) ?? null,
|
||||
[segmentationModels, selectedSegmentationModelId],
|
||||
)
|
||||
const selectedMapArea = useMemo(
|
||||
() => areas.find((area) => area.id === selectedMapAreaId) ?? null,
|
||||
[areas, selectedMapAreaId],
|
||||
)
|
||||
const areaFeatureCollection = useMemo<GeoJSON.FeatureCollection | null>(() => {
|
||||
if (!selectedMapArea?.geometry) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
geometry: selectedMapArea.geometry,
|
||||
properties: {
|
||||
layer_type: 'project_area',
|
||||
area_id: selectedMapArea.id,
|
||||
name: selectedMapArea.name,
|
||||
area_m2: selectedMapArea.area_m2 ?? null,
|
||||
original_crs: selectedMapArea.original_crs ?? null,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}, [selectedMapArea])
|
||||
const mapFeatureCollection = useMemo(
|
||||
() => changeDetectionResult?.geojson ?? segmentationGeoJson ?? detectionGeoJson ?? datasetContent,
|
||||
[changeDetectionResult, segmentationGeoJson, detectionGeoJson, datasetContent],
|
||||
@@ -263,6 +291,7 @@ function App(): JSX.Element {
|
||||
return 'No active vector layer'
|
||||
}, [changeDetectionResult, datasetContent, detectionGeoJson, segmentationGeoJson, selectedDataset])
|
||||
const mapFeatureCount = mapFeatureCollection?.features.length ?? 0
|
||||
const areaFeatureCount = areaFeatureCollection?.features.length ?? 0
|
||||
const isRasterTileInputValid = useMemo(
|
||||
() => rasterTileSize > 0 && rasterTileOverlap >= 0 && rasterTileOverlap < rasterTileSize,
|
||||
[rasterTileSize, rasterTileOverlap],
|
||||
@@ -313,6 +342,11 @@ function App(): JSX.Element {
|
||||
if (!selectedClipAreaId && areaResponse.items.length > 0) {
|
||||
setSelectedClipAreaId(areaResponse.items[0].id)
|
||||
}
|
||||
if (areaResponse.items.length === 0) {
|
||||
setSelectedMapAreaId('')
|
||||
} else if (!selectedMapAreaId || !areaResponse.items.some((area) => area.id === selectedMapAreaId)) {
|
||||
setSelectedMapAreaId(areaResponse.items[0].id)
|
||||
}
|
||||
} catch (error) {
|
||||
setErrorMessage(error instanceof Error ? error.message : 'Failed to load project data')
|
||||
} finally {
|
||||
@@ -645,7 +679,7 @@ function App(): JSX.Element {
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedMapFeature(null)
|
||||
}, [mapFeatureCollection])
|
||||
}, [mapFeatureCollection, areaFeatureCollection])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedProjectId) {
|
||||
@@ -653,6 +687,7 @@ function App(): JSX.Element {
|
||||
setDatasets([])
|
||||
setSelectedDatasetId(null)
|
||||
setSelectedDataset(null)
|
||||
setSelectedMapAreaId('')
|
||||
setSelectedDatasetSummary(null)
|
||||
setSelectedRasterMetadata(null)
|
||||
setSelectedRasterStats(null)
|
||||
@@ -716,6 +751,7 @@ function App(): JSX.Element {
|
||||
const result = await demoApi.seedWorkflow()
|
||||
setSelectedProjectId(result.project_id)
|
||||
setSelectedDatasetId(result.candidate_dataset_id)
|
||||
setSelectedMapAreaId(result.area_id)
|
||||
setQaCandidateDatasetId(result.candidate_dataset_id)
|
||||
setQaReferenceDatasetId(result.reference_dataset_id)
|
||||
setQaAreaId(result.area_id)
|
||||
@@ -751,11 +787,12 @@ function App(): JSX.Element {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await areasApi.create(selectedProjectId, {
|
||||
const createdArea = await areasApi.create(selectedProjectId, {
|
||||
name: areaForm.name,
|
||||
crs: areaForm.crs,
|
||||
geometry,
|
||||
})
|
||||
setSelectedMapAreaId(createdArea.id)
|
||||
await loadProjectData(selectedProjectId)
|
||||
setAreaForm((previous) => ({ ...previous, name: '' }))
|
||||
} catch (error) {
|
||||
@@ -1349,8 +1386,10 @@ function App(): JSX.Element {
|
||||
selectedProjectId={selectedProjectId}
|
||||
loadingAreas={loadingAreas}
|
||||
areaForm={areaForm}
|
||||
selectedMapAreaId={selectedMapAreaId}
|
||||
onCreateArea={createArea}
|
||||
onUpdateAreaForm={setAreaForm}
|
||||
onSelectMapArea={setSelectedMapAreaId}
|
||||
/>
|
||||
|
||||
<ProviderPanel
|
||||
@@ -1851,6 +1890,42 @@ function App(): JSX.Element {
|
||||
<h2>Map workspace</h2>
|
||||
<p>{mapLayerLabel}</p>
|
||||
<div className="map-controls">
|
||||
<label>
|
||||
Selected area
|
||||
<select
|
||||
value={selectedMapAreaId}
|
||||
onChange={(event) => setSelectedMapAreaId(event.target.value)}
|
||||
disabled={areas.length === 0}
|
||||
>
|
||||
<option value="">No area</option>
|
||||
{areas.map((area) => (
|
||||
<option key={area.id} value={area.id}>
|
||||
{area.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="checkbox-row">
|
||||
<input
|
||||
checked={areaLayerVisible}
|
||||
disabled={!areaFeatureCollection}
|
||||
type="checkbox"
|
||||
onChange={(event) => setAreaLayerVisible(event.target.checked)}
|
||||
/>
|
||||
Area visible
|
||||
</label>
|
||||
<label>
|
||||
Area opacity
|
||||
<input
|
||||
disabled={!areaFeatureCollection}
|
||||
max="0.7"
|
||||
min="0.05"
|
||||
step="0.05"
|
||||
type="range"
|
||||
value={areaLayerOpacity}
|
||||
onChange={(event) => setAreaLayerOpacity(Number(event.target.value))}
|
||||
/>
|
||||
</label>
|
||||
<label className="checkbox-row">
|
||||
<input
|
||||
checked={mapLayerVisible}
|
||||
@@ -1873,13 +1948,17 @@ function App(): JSX.Element {
|
||||
/>
|
||||
</label>
|
||||
<div className="map-status">
|
||||
{areaFeatureCollection ? `${areaFeatureCount} area loaded` : 'No area loaded'} -{' '}
|
||||
{mapFeatureCollection ? `${mapFeatureCount} features loaded` : 'No vector layer loaded'}
|
||||
</div>
|
||||
</div>
|
||||
<GeoMap
|
||||
data={mapFeatureCollection}
|
||||
areaData={areaFeatureCollection}
|
||||
visible={mapLayerVisible}
|
||||
opacity={mapLayerOpacity}
|
||||
areaVisible={areaLayerVisible}
|
||||
areaOpacity={areaLayerOpacity}
|
||||
onFeatureSelect={setSelectedMapFeature}
|
||||
/>
|
||||
<div className="feature-inspector">
|
||||
|
||||
Reference in New Issue
Block a user