fix: align Mol explorer primary metrics
This commit is contained in:
@@ -23,6 +23,8 @@ def test_map_first_explorer_is_the_default_product_flow() -> None:
|
|||||||
assert "Bron nog niet ingeladen" in workspace
|
assert "Bron nog niet ingeladen" in workspace
|
||||||
assert "useMapThemeSelectionInsights" in workspace
|
assert "useMapThemeSelectionInsights" in workspace
|
||||||
assert "datasetsApi.selectVectorFeatures" in read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
assert "datasetsApi.selectVectorFeatures" in read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
||||||
|
assert "activeSelectionResult" in workspace
|
||||||
|
assert "bboxesEqual(mapSelectionBbox, selectedAreaBbox)" in workspace
|
||||||
|
|
||||||
|
|
||||||
def test_map_rectangle_drag_is_wired_to_automatic_analysis() -> None:
|
def test_map_rectangle_drag_is_wired_to_automatic_analysis() -> None:
|
||||||
|
|||||||
@@ -735,7 +735,7 @@ function App(): JSX.Element {
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main className="workbench-main" id="workspace-main" tabIndex={-1}>
|
<main className="workbench-main" id="workspace-main" tabIndex={-1}>
|
||||||
<div className="workspace-heading">
|
{activeWorkspace !== 'map' ? <div className="workspace-heading">
|
||||||
<div className="workspace-heading-copy">
|
<div className="workspace-heading-copy">
|
||||||
<p className="eyebrow">{selectedProject?.region ?? 'Mol, Kempen'}</p>
|
<p className="eyebrow">{selectedProject?.region ?? 'Mol, Kempen'}</p>
|
||||||
<h2>{activeWorkspaceItem.label}</h2>
|
<h2>{activeWorkspaceItem.label}</h2>
|
||||||
@@ -754,7 +754,7 @@ function App(): JSX.Element {
|
|||||||
</button>
|
</button>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> : null}
|
||||||
<div className="workspace-command-bar" aria-label="Workspace shortcuts">
|
<div className="workspace-command-bar" aria-label="Workspace shortcuts">
|
||||||
<div className="workspace-nav-cluster">
|
<div className="workspace-nav-cluster">
|
||||||
{workspaceNavItems.slice(0, 5).map((item) => (
|
{workspaceNavItems.slice(0, 5).map((item) => (
|
||||||
|
|||||||
@@ -106,6 +106,19 @@ function selectionAreaSquareMetres(bbox: VectorSelectionBBox | null): number | n
|
|||||||
return Math.max(0, widthMetres * heightMetres)
|
return Math.max(0, widthMetres * heightMetres)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bboxesEqual(left: VectorSelectionBBox | null, right: VectorSelectionBBox | null): boolean {
|
||||||
|
if (!left || !right) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const tolerance = 1e-9
|
||||||
|
return (
|
||||||
|
Math.abs(left.min_x - right.min_x) < tolerance &&
|
||||||
|
Math.abs(left.min_y - right.min_y) < tolerance &&
|
||||||
|
Math.abs(left.max_x - right.max_x) < tolerance &&
|
||||||
|
Math.abs(left.max_y - right.max_y) < tolerance
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function formatArea(areaSquareMetres: number | null): string {
|
function formatArea(areaSquareMetres: number | null): string {
|
||||||
if (areaSquareMetres === null) {
|
if (areaSquareMetres === null) {
|
||||||
return 'Nog niet geselecteerd'
|
return 'Nog niet geselecteerd'
|
||||||
@@ -469,14 +482,29 @@ export function MapWorkspace({
|
|||||||
)
|
)
|
||||||
const activeTheme = DATA_THEMES.find((theme) => theme.id === activeThemeId) ?? DATA_THEMES[0]
|
const activeTheme = DATA_THEMES.find((theme) => theme.id === activeThemeId) ?? DATA_THEMES[0]
|
||||||
const activeThemeDataset = themeDatasetMap[activeTheme.id]
|
const activeThemeDataset = themeDatasetMap[activeTheme.id]
|
||||||
const selectedAreaSquareMetres = useMemo(() => selectionAreaSquareMetres(mapSelectionBbox), [mapSelectionBbox])
|
const themeResults = useMemo(
|
||||||
const selectedResultTotal = mapSelectionResult?.total_feature_count ?? mapSelectionResult?.feature_count ?? 0
|
() =>
|
||||||
|
themeInsights.flatMap((insight) => {
|
||||||
|
const theme = DATA_THEMES.find((candidate) => candidate.id === insight.themeId)
|
||||||
|
return theme ? [{ theme, dataset: insight.dataset, result: insight.result }] : []
|
||||||
|
}),
|
||||||
|
[themeInsights],
|
||||||
|
)
|
||||||
|
const activeSelectionResult = themeResults.find((item) => item.theme.id === activeThemeId)?.result ?? mapSelectionResult
|
||||||
|
const selectedAreaSquareMetres = useMemo(
|
||||||
|
() =>
|
||||||
|
bboxesEqual(mapSelectionBbox, selectedAreaBbox) && selectedMapArea?.area_m2
|
||||||
|
? selectedMapArea.area_m2
|
||||||
|
: selectionAreaSquareMetres(mapSelectionBbox),
|
||||||
|
[mapSelectionBbox, selectedAreaBbox, selectedMapArea?.area_m2],
|
||||||
|
)
|
||||||
|
const selectedResultTotal = activeSelectionResult?.total_feature_count ?? activeSelectionResult?.feature_count ?? 0
|
||||||
const selectedDensity = selectedAreaSquareMetres && selectedAreaSquareMetres > 0
|
const selectedDensity = selectedAreaSquareMetres && selectedAreaSquareMetres > 0
|
||||||
? selectedResultTotal / (selectedAreaSquareMetres / 1_000_000)
|
? selectedResultTotal / (selectedAreaSquareMetres / 1_000_000)
|
||||||
: null
|
: null
|
||||||
const selectedResultProperties = useMemo(() => {
|
const selectedResultProperties = useMemo(() => {
|
||||||
const keys = new Map<string, Set<string>>()
|
const keys = new Map<string, Set<string>>()
|
||||||
for (const feature of mapSelectionResult?.geojson.features ?? []) {
|
for (const feature of activeSelectionResult?.geojson.features ?? []) {
|
||||||
for (const [key, value] of Object.entries(feature.properties ?? {})) {
|
for (const [key, value] of Object.entries(feature.properties ?? {})) {
|
||||||
if (value === null || value === undefined || typeof value === 'object' || key.endsWith('_id')) {
|
if (value === null || value === undefined || typeof value === 'object' || key.endsWith('_id')) {
|
||||||
continue
|
continue
|
||||||
@@ -492,26 +520,18 @@ export function MapWorkspace({
|
|||||||
.filter(([, values]) => values.size > 0)
|
.filter(([, values]) => values.size > 0)
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
.map(([key, values]) => ({ key, values: Array.from(values) }))
|
.map(([key, values]) => ({ key, values: Array.from(values) }))
|
||||||
}, [mapSelectionResult])
|
}, [activeSelectionResult])
|
||||||
const themeResults = useMemo(
|
|
||||||
() =>
|
|
||||||
themeInsights.flatMap((insight) => {
|
|
||||||
const theme = DATA_THEMES.find((candidate) => candidate.id === insight.themeId)
|
|
||||||
return theme ? [{ theme, dataset: insight.dataset, result: insight.result }] : []
|
|
||||||
}),
|
|
||||||
[themeInsights],
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setBboxInput(bboxToInputState(mapSelectionBbox))
|
setBboxInput(bboxToInputState(mapSelectionBbox))
|
||||||
}, [mapSelectionBbox])
|
}, [mapSelectionBbox])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedMapDatasetId || !themeDatasetMap.buildings) {
|
if (advancedMode || !activeThemeDataset || (selectedMapDataset && datasetMatchesTheme(selectedMapDataset, activeTheme))) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
onOpenDatasetInMap(themeDatasetMap.buildings)
|
onOpenDatasetInMap(activeThemeDataset)
|
||||||
}, [onOpenDatasetInMap, selectedMapDatasetId, themeDatasetMap.buildings])
|
}, [activeTheme, activeThemeDataset, advancedMode, onOpenDatasetInMap, selectedMapDataset])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedMapDataset) {
|
if (!selectedMapDataset) {
|
||||||
@@ -883,7 +903,7 @@ export function MapWorkspace({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>{activeTheme.shortLabel}</span>
|
<span>{activeTheme.shortLabel}</span>
|
||||||
<strong>{mapSelectionResult ? resultCountLabel(mapSelectionResult) : 'Geen resultaat'}</strong>
|
<strong>{activeSelectionResult ? resultCountLabel(activeSelectionResult) : 'Geen resultaat'}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Dichtheid</span>
|
<span>Dichtheid</span>
|
||||||
@@ -912,8 +932,8 @@ export function MapWorkspace({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{mapSelectionResult?.truncated ? (
|
{activeSelectionResult?.truncated ? (
|
||||||
<p className="geo-data-notice">De telling is volledig; op de kaart en in de tabel worden maximaal {mapSelectionResult.limit.toLocaleString('nl-BE')} objecten getoond.</p>
|
<p className="geo-data-notice">De telling is volledig; op de kaart en in de tabel worden maximaal {activeSelectionResult.limit.toLocaleString('nl-BE')} objecten getoond.</p>
|
||||||
) : null}
|
) : null}
|
||||||
{mapSelectionError ? <p className="error">{mapSelectionError}</p> : null}
|
{mapSelectionError ? <p className="error">{mapSelectionError}</p> : null}
|
||||||
{themeResultsError ? <p className="error">{themeResultsError}</p> : null}
|
{themeResultsError ? <p className="error">{themeResultsError}</p> : null}
|
||||||
|
|||||||
Reference in New Issue
Block a user