Refactor map page
This commit is contained in:
parent
29d048ffd4
commit
d4d79f0d99
17 changed files with 1014 additions and 878 deletions
|
|
@ -4,7 +4,7 @@ const INITIAL_RETRY_MS = 1000;
|
|||
const MAX_RETRY_MS = 10000;
|
||||
|
||||
// Error handling utilities
|
||||
export function isAbortError(error: unknown): boolean {
|
||||
function isAbortError(error: unknown): boolean {
|
||||
return error instanceof Error && error.name === 'AbortError';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
import type { ViewState } from '../types';
|
||||
|
||||
// =============================================================================
|
||||
// Map Bounds & Zoom
|
||||
// =============================================================================
|
||||
|
||||
/** Geographic bounds constraining map panning [west, south, east, north] */
|
||||
export const MAP_BOUNDS: [number, number, number, number] = [-9.5, 49, 5, 57];
|
||||
|
||||
/** Minimum zoom level (can't zoom out further) */
|
||||
export const MAP_MIN_ZOOM = 5.5;
|
||||
|
||||
/** Maximum zoom level for tile fetching (map extrapolates beyond this) */
|
||||
|
|
@ -21,12 +14,6 @@ export const INITIAL_VIEW_STATE: ViewState = {
|
|||
pitch: 0,
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Zoom Thresholds
|
||||
// =============================================================================
|
||||
|
||||
/** Zoom level at which we switch from H3 hexagons to postcode polygons */
|
||||
export const POSTCODE_ZOOM_THRESHOLD = 15;
|
||||
|
||||
/**
|
||||
* Zoom to H3 resolution mapping thresholds.
|
||||
|
|
@ -40,6 +27,8 @@ export const ZOOM_TO_RESOLUTION_THRESHOLDS = [
|
|||
{ maxZoom: 13, resolution: 9 },
|
||||
{ maxZoom: Infinity, resolution: 10 },
|
||||
] as const;
|
||||
export const POSTCODE_ZOOM_THRESHOLD = 15;
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// Color Gradients
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
import type { FeatureMeta } from '../types';
|
||||
|
||||
export interface FeatureGroup {
|
||||
name: string;
|
||||
features: FeatureMeta[];
|
||||
}
|
||||
import type { FeatureMeta, FeatureGroup } from '../types';
|
||||
|
||||
export function groupFeaturesByCategory(features: FeatureMeta[]): FeatureGroup[] {
|
||||
const groups: FeatureGroup[] = [];
|
||||
|
|
|
|||
|
|
@ -35,13 +35,15 @@ export function getMapStyle(theme: 'light' | 'dark'): StyleSpecification {
|
|||
} as StyleSpecification;
|
||||
}
|
||||
|
||||
export function normalizedToColor(t: number): [number, number, number] {
|
||||
if (t <= 0) return FEATURE_GRADIENT[0].color;
|
||||
if (t >= 1) return FEATURE_GRADIENT[FEATURE_GRADIENT.length - 1].color;
|
||||
type GradientStop = { t: number; color: [number, number, number] };
|
||||
|
||||
for (let i = 0; i < FEATURE_GRADIENT.length - 1; i++) {
|
||||
const lo = FEATURE_GRADIENT[i];
|
||||
const hi = FEATURE_GRADIENT[i + 1];
|
||||
function interpolateGradient(t: number, gradient: GradientStop[]): [number, number, number] {
|
||||
if (t <= 0) return gradient[0].color;
|
||||
if (t >= 1) return gradient[gradient.length - 1].color;
|
||||
|
||||
for (let i = 0; i < gradient.length - 1; i++) {
|
||||
const lo = gradient[i];
|
||||
const hi = gradient[i + 1];
|
||||
if (t >= lo.t && t <= hi.t) {
|
||||
const frac = (t - lo.t) / (hi.t - lo.t);
|
||||
return [
|
||||
|
|
@ -51,26 +53,15 @@ export function normalizedToColor(t: number): [number, number, number] {
|
|||
];
|
||||
}
|
||||
}
|
||||
return FEATURE_GRADIENT[FEATURE_GRADIENT.length - 1].color;
|
||||
return gradient[gradient.length - 1].color;
|
||||
}
|
||||
|
||||
export function normalizedToColor(t: number): [number, number, number] {
|
||||
return interpolateGradient(t, FEATURE_GRADIENT);
|
||||
}
|
||||
|
||||
export function countToColor(t: number): [number, number, number] {
|
||||
if (t <= 0) return DENSITY_GRADIENT[0].color;
|
||||
if (t >= 1) return DENSITY_GRADIENT[DENSITY_GRADIENT.length - 1].color;
|
||||
|
||||
for (let i = 0; i < DENSITY_GRADIENT.length - 1; i++) {
|
||||
const lo = DENSITY_GRADIENT[i];
|
||||
const hi = DENSITY_GRADIENT[i + 1];
|
||||
if (t >= lo.t && t <= hi.t) {
|
||||
const frac = (t - lo.t) / (hi.t - lo.t);
|
||||
return [
|
||||
Math.round(lo.color[0] + (hi.color[0] - lo.color[0]) * frac),
|
||||
Math.round(lo.color[1] + (hi.color[1] - lo.color[1]) * frac),
|
||||
Math.round(lo.color[2] + (hi.color[2] - lo.color[2]) * frac),
|
||||
];
|
||||
}
|
||||
}
|
||||
return DENSITY_GRADIENT[DENSITY_GRADIENT.length - 1].color;
|
||||
return interpolateGradient(t, DENSITY_GRADIENT);
|
||||
}
|
||||
|
||||
export function zoomToResolution(zoom: number): number {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
import type { FeatureMeta, FeatureFilters, ViewState } from '../types';
|
||||
|
||||
export const DEFAULT_VIEW: ViewState = {
|
||||
longitude: -1.5,
|
||||
latitude: 53.5,
|
||||
zoom: 6,
|
||||
pitch: 0,
|
||||
};
|
||||
|
||||
export function parseUrlState(): {
|
||||
viewState?: ViewState;
|
||||
filters?: FeatureFilters;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue