This commit is contained in:
Andras Schmelczer 2026-02-18 21:22:15 +00:00
parent 524580eb25
commit ffe080adef
82 changed files with 2652 additions and 2956 deletions

View file

@ -11,7 +11,7 @@ import type {
import { buildFilterString, apiUrl, assertOk, logNonAbortError, authHeaders, isAbortError } from '../lib/api';
import { POSTCODE_ZOOM_THRESHOLD } from '../lib/consts';
import { COLOR_RANGE_LOW_PERCENTILE, COLOR_RANGE_HIGH_PERCENTILE } from '../lib/consts';
import { type TravelTimeEntry, travelFieldKey } from './useTravelTime';
import { type TravelTimeEntry } from './useTravelTime';
/** Return the p-th percentile (0100) from a sorted array via linear interpolation. */
function percentile(sorted: number[], p: number): number {
@ -107,7 +107,7 @@ export function useMapData({
if (usePostcodeView) {
const params = new URLSearchParams({ bounds: boundsStr });
if (filtersStr) params.set('filters', filtersStr);
params.set('fields', viewFeature || '');
params.set('fields', viewFeature && !viewFeature.startsWith('tt_') ? viewFeature : '');
const res = await fetch(
apiUrl('postcodes', params),
authHeaders({
@ -133,7 +133,7 @@ export function useMapData({
bounds: boundsStr,
});
if (filtersStr) params.set('filters', filtersStr);
params.set('fields', viewFeature || '');
params.set('fields', viewFeature && !viewFeature.startsWith('tt_') ? viewFeature : '');
if (travelParam) {
params.set('travel', travelParam);
}
@ -176,14 +176,18 @@ export function useMapData({
// Compute p5/p95 from visible data for the viewed feature
const dataRange = useMemo((): [number, number] | null => {
if (!viewFeature) return null;
const meta = features.find((f) => f.name === viewFeature);
if (!meta || meta.type === 'enum') return null;
if (activeFeature && !dragData) return null;
const isTravelTime = viewFeature.startsWith('tt_');
if (!isTravelTime) {
const meta = features.find((f) => f.name === viewFeature);
if (!meta || meta.type === 'enum') return null;
if (activeFeature && !dragData) return null;
}
const vals: number[] = [];
if (usePostcodeView) {
if (usePostcodeView && !isTravelTime) {
if (postcodeData.length === 0) return null;
for (const feat of postcodeData) {
if (bounds) {
@ -218,6 +222,12 @@ export function useMapData({
// Color range for the legend and hex coloring
const colorRange = useMemo((): [number, number] | null => {
if (!viewFeature) return null;
// Travel time keys: use dataRange directly (no FeatureMeta)
if (viewFeature.startsWith('tt_')) {
return dataRange;
}
const meta = features.find((f) => f.name === viewFeature);
if (!meta) return null;
if (meta.type === 'enum' && meta.values && meta.values.length > 0) {
@ -229,33 +239,6 @@ export function useMapData({
return null;
}, [viewFeature, features, dataRange, activeFeature, dragValue]);
// Color ranges for travel time per entry (computed from response data)
const travelTimeColorRanges = useMemo((): Map<number, [number, number]> => {
const ranges = new Map<number, [number, number]>();
for (let i = 0; i < travelTimeEntries.length; i++) {
const entry = travelTimeEntries[i];
if (!entry.slug) continue;
const fieldName = `avg_${travelFieldKey(entry)}`;
const vals: number[] = [];
for (const item of data) {
if (bounds) {
const { lat, lon } = item;
if (lat < bounds.south || lat > bounds.north || lon < bounds.west || lon > bounds.east)
continue;
}
const val = item[fieldName];
if (typeof val === 'number' && !isNaN(val)) vals.push(val);
}
if (vals.length === 0) continue;
vals.sort((a, b) => a - b);
ranges.set(i, [
percentile(vals, COLOR_RANGE_LOW_PERCENTILE),
percentile(vals, COLOR_RANGE_HIGH_PERCENTILE),
]);
}
return ranges;
}, [travelTimeEntries, data, bounds]);
const handleViewChange = useCallback(
({
resolution: newRes,
@ -295,7 +278,6 @@ export function useMapData({
currentView,
usePostcodeView,
colorRange,
travelTimeColorRanges,
handleViewChange,
setInitialView,
licenseRequired,