Last night
This commit is contained in:
parent
2906b01734
commit
42ee2d4c51
47 changed files with 848 additions and 478 deletions
|
|
@ -10,6 +10,19 @@ import type {
|
|||
} from '../types';
|
||||
import { buildFilterString, apiUrl, logNonAbortError, authHeaders } from '../lib/api';
|
||||
import { POSTCODE_ZOOM_THRESHOLD } from '../lib/map-utils';
|
||||
import { COLOR_RANGE_LOW_PERCENTILE, COLOR_RANGE_HIGH_PERCENTILE } from '../lib/consts';
|
||||
import { cellToLatLng } from 'h3-js';
|
||||
|
||||
/** Return the p-th percentile (0–100) from a sorted array via linear interpolation. */
|
||||
function percentile(sorted: number[], p: number): number {
|
||||
if (sorted.length === 0) return 0;
|
||||
if (sorted.length === 1) return sorted[0];
|
||||
const idx = (p / 100) * (sorted.length - 1);
|
||||
const lo = Math.floor(idx);
|
||||
const hi = Math.ceil(idx);
|
||||
if (lo === hi) return sorted[lo];
|
||||
return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);
|
||||
}
|
||||
|
||||
const DEBOUNCE_MS = 150;
|
||||
|
||||
|
|
@ -118,7 +131,8 @@ export function useMapData({
|
|||
|
||||
const data = dragData ?? rawData;
|
||||
|
||||
// Compute actual min/max from visible data for the viewed feature
|
||||
// Compute p5/p95 from visible data for the viewed feature
|
||||
// Only considers hexagons/postcodes whose center falls within the viewport bounds
|
||||
const dataRange = useMemo((): [number, number] | null => {
|
||||
if (!viewFeature) return null;
|
||||
const meta = features.find((f) => f.name === viewFeature);
|
||||
|
|
@ -126,32 +140,34 @@ export function useMapData({
|
|||
|
||||
if (activeFeature && !dragData) return null;
|
||||
|
||||
let min = Infinity;
|
||||
let max = -Infinity;
|
||||
const vals: number[] = [];
|
||||
|
||||
if (usePostcodeView) {
|
||||
if (postcodeData.length === 0) return null;
|
||||
for (const feat of postcodeData) {
|
||||
const val = feat.properties[`min_${viewFeature}`];
|
||||
if (typeof val === 'number' && !isNaN(val)) {
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
if (bounds) {
|
||||
const [lng, lat] = feat.properties.centroid as [number, number];
|
||||
if (lat < bounds.south || lat > bounds.north || lng < bounds.west || lng > bounds.east) continue;
|
||||
}
|
||||
const val = feat.properties[`avg_${viewFeature}`] ?? feat.properties[`min_${viewFeature}`];
|
||||
if (typeof val === 'number' && !isNaN(val)) vals.push(val);
|
||||
}
|
||||
} else {
|
||||
if (data.length === 0) return null;
|
||||
for (const item of data) {
|
||||
const val = item[`min_${viewFeature}`];
|
||||
if (typeof val === 'number' && !isNaN(val)) {
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
if (bounds) {
|
||||
const [lat, lng] = cellToLatLng(item.h3);
|
||||
if (lat < bounds.south || lat > bounds.north || lng < bounds.west || lng > bounds.east) continue;
|
||||
}
|
||||
const val = item[`avg_${viewFeature}`] ?? item[`min_${viewFeature}`];
|
||||
if (typeof val === 'number' && !isNaN(val)) vals.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
if (min === Infinity || max === -Infinity) return null;
|
||||
return [min, max];
|
||||
}, [viewFeature, data, dragData, postcodeData, usePostcodeView, features, activeFeature]);
|
||||
if (vals.length === 0) return null;
|
||||
vals.sort((a, b) => a - b);
|
||||
return [percentile(vals, COLOR_RANGE_LOW_PERCENTILE), percentile(vals, COLOR_RANGE_HIGH_PERCENTILE)];
|
||||
}, [viewFeature, data, dragData, postcodeData, usePostcodeView, features, activeFeature, bounds]);
|
||||
|
||||
// Color range for the legend and hex coloring
|
||||
const colorRange = useMemo((): [number, number] | null => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue