fix(map): bound overview feature payloads
This commit is contained in:
@@ -10999,6 +10999,10 @@ rasters could still enter a Belgium-scale analysis. The shared selection guard
|
|||||||
now applies the same real pixel budgets to persisted rasters: country-scale
|
now applies the same real pixel budgets to persisted rasters: country-scale
|
||||||
overview analysis keeps PostGIS vector and national statistical sources, while
|
overview analysis keeps PostGIS vector and national statistical sources, while
|
||||||
high-resolution rasters require detail or safely bounded regional extent.
|
high-resolution rasters require detail or safely bounded regional extent.
|
||||||
|
Overview responses now return at most 25 representative GeoJSON features per
|
||||||
|
source (250 regionally, 1,000 in detail) while `total_feature_count` and every
|
||||||
|
PostGIS metric continue to cover the complete selection. This prevents large
|
||||||
|
profile properties from blocking the browser without weakening measurements.
|
||||||
|
|
||||||
Validation:
|
Validation:
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import {
|
|||||||
selectionAnalysisScale,
|
selectionAnalysisScale,
|
||||||
selectionAreaSquareMetres,
|
selectionAreaSquareMetres,
|
||||||
selectionDimensions,
|
selectionDimensions,
|
||||||
|
selectionFeatureLimit,
|
||||||
selectionMetricLabel,
|
selectionMetricLabel,
|
||||||
splitSelectionBbox,
|
splitSelectionBbox,
|
||||||
} from './mapWorkspaceUtils'
|
} from './mapWorkspaceUtils'
|
||||||
@@ -1830,12 +1831,14 @@ export function MapWorkspace({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const availableThemes: Array<MapThemeQuery<DataThemeId>> = []
|
const availableThemes: Array<MapThemeQuery<DataThemeId>> = []
|
||||||
|
const resultFeatureLimit = selectionFeatureLimit(bbox)
|
||||||
for (const theme of DATA_THEMES) {
|
for (const theme of DATA_THEMES) {
|
||||||
const dataset = themeDatasetMap[theme.id]
|
const dataset = themeDatasetMap[theme.id]
|
||||||
if (dataset && persistedDatasetSupportsSelection(dataset, bbox)) {
|
if (dataset && persistedDatasetSupportsSelection(dataset, bbox)) {
|
||||||
availableThemes.push({
|
availableThemes.push({
|
||||||
themeId: theme.id,
|
themeId: theme.id,
|
||||||
dataset,
|
dataset,
|
||||||
|
featureLimit: resultFeatureLimit,
|
||||||
partitioned: regionalScopeSelected
|
partitioned: regionalScopeSelected
|
||||||
&& (isPartitionedRaster(dataset) || isPartitionedBathymetry(dataset)),
|
&& (isPartitionedRaster(dataset) || isPartitionedBathymetry(dataset)),
|
||||||
})
|
})
|
||||||
@@ -1852,6 +1855,7 @@ export function MapWorkspace({
|
|||||||
displayName: onDemandProduct.displayName,
|
displayName: onDemandProduct.displayName,
|
||||||
},
|
},
|
||||||
acquisitionBboxes: onDemandProduct.acquisitionBboxes,
|
acquisitionBboxes: onDemandProduct.acquisitionBboxes,
|
||||||
|
featureLimit: resultFeatureLimit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
selectionAnalysisScale,
|
selectionAnalysisScale,
|
||||||
selectionAreaSquareMetres,
|
selectionAreaSquareMetres,
|
||||||
selectionDimensions,
|
selectionDimensions,
|
||||||
|
selectionFeatureLimit,
|
||||||
splitSelectionBbox,
|
splitSelectionBbox,
|
||||||
} from './mapWorkspaceUtils'
|
} from './mapWorkspaceUtils'
|
||||||
import type { VectorSelectionBBox, VectorSelectionResponse } from '../../types'
|
import type { VectorSelectionBBox, VectorSelectionResponse } from '../../types'
|
||||||
@@ -156,5 +157,7 @@ describe('map workspace selection guards', () => {
|
|||||||
{ dataset_type: 'vector', source_name: 'statbel' },
|
{ dataset_type: 'vector', source_name: 'statbel' },
|
||||||
overview,
|
overview,
|
||||||
)).toBe(true)
|
)).toBe(true)
|
||||||
|
expect(selectionFeatureLimit(overview)).toBe(25)
|
||||||
|
expect(selectionFeatureLimit({ ...overview, min_x: 5, max_x: 5.1, min_y: 51, max_y: 51.1 })).toBe(1000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -117,6 +117,13 @@ export function persistedDatasetSupportsSelection(
|
|||||||
return scale === 'detail'
|
return scale === 'detail'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function selectionFeatureLimit(bbox: VectorSelectionBBox): number {
|
||||||
|
const scale = selectionAnalysisScale(bbox)
|
||||||
|
if (scale === 'overview') return 25
|
||||||
|
if (scale === 'regional') return 250
|
||||||
|
return 1000
|
||||||
|
}
|
||||||
|
|
||||||
export function splitSelectionBbox(
|
export function splitSelectionBbox(
|
||||||
bbox: VectorSelectionBBox,
|
bbox: VectorSelectionBBox,
|
||||||
maxTileSideMetres = 18_000,
|
maxTileSideMetres = 18_000,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export interface MapThemeQuery<TThemeId extends string> {
|
|||||||
partitioned?: boolean
|
partitioned?: boolean
|
||||||
acquisition?: MapThemeAcquisition
|
acquisition?: MapThemeAcquisition
|
||||||
acquisitionBboxes?: VectorSelectionBBox[]
|
acquisitionBboxes?: VectorSelectionBBox[]
|
||||||
|
featureLimit?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MapThemeInsight<TThemeId extends string> {
|
export interface MapThemeInsight<TThemeId extends string> {
|
||||||
@@ -104,9 +105,10 @@ export function useMapThemeSelectionInsights<TThemeId extends string>(
|
|||||||
const settled = await settleWithConcurrency(
|
const settled = await settleWithConcurrency(
|
||||||
queries,
|
queries,
|
||||||
3,
|
3,
|
||||||
async ({ themeId, dataset: existingDataset, partitioned, acquisition, acquisitionBboxes }) => {
|
async ({ themeId, dataset: existingDataset, partitioned, acquisition, acquisitionBboxes, featureLimit }) => {
|
||||||
let dataset = existingDataset
|
let dataset = existingDataset
|
||||||
let acquiredDatasets: DatasetCreateResponse[] = []
|
let acquiredDatasets: DatasetCreateResponse[] = []
|
||||||
|
const resultLimit = featureLimit ?? 1000
|
||||||
if (acquisition) {
|
if (acquisition) {
|
||||||
const requestedBboxes = acquisitionBboxes?.length ? acquisitionBboxes : [bbox]
|
const requestedBboxes = acquisitionBboxes?.length ? acquisitionBboxes : [bbox]
|
||||||
const acquisitionResults = await settleWithConcurrency(requestedBboxes, 1, async (acquisitionBbox) => {
|
const acquisitionResults = await settleWithConcurrency(requestedBboxes, 1, async (acquisitionBbox) => {
|
||||||
@@ -209,18 +211,18 @@ export function useMapThemeSelectionInsights<TThemeId extends string>(
|
|||||||
dataset_ids: acquiredDatasetIds,
|
dataset_ids: acquiredDatasetIds,
|
||||||
bbox,
|
bbox,
|
||||||
area_id: areaId,
|
area_id: areaId,
|
||||||
limit: 1000,
|
limit: resultLimit,
|
||||||
})
|
})
|
||||||
: dataset.source_name === 'vmm_vha_bathymetry_profiles' && partitioned
|
: dataset.source_name === 'vmm_vha_bathymetry_profiles' && partitioned
|
||||||
? await datasetsApi.selectBathymetryProfilePartitions(selectedProjectId, {
|
? await datasetsApi.selectBathymetryProfilePartitions(selectedProjectId, {
|
||||||
bbox,
|
bbox,
|
||||||
area_id: areaId,
|
area_id: areaId,
|
||||||
limit: 1000,
|
limit: resultLimit,
|
||||||
})
|
})
|
||||||
: await datasetsApi.selectVectorFeatures(selectedProjectId, dataset.id, {
|
: await datasetsApi.selectVectorFeatures(selectedProjectId, dataset.id, {
|
||||||
bbox,
|
bbox,
|
||||||
area_id: areaId,
|
area_id: areaId,
|
||||||
limit: 1000,
|
limit: resultLimit,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user