186 lines
5.2 KiB
TypeScript
186 lines
5.2 KiB
TypeScript
import type { ViewState } from '../types';
|
|
|
|
|
|
export const INITIAL_RETRY_MS = 1000;
|
|
export const MAX_RETRY_MS = 10000;
|
|
|
|
|
|
export const MAP_BOUNDS: [number, number, number, number] = [-9.5, 49, 5, 57];
|
|
export const MAP_MIN_ZOOM = 5.5;
|
|
|
|
export const BUFFER_MULTIPLIER = 1.5;
|
|
|
|
export const INITIAL_VIEW_STATE: ViewState = {
|
|
longitude: -1.5,
|
|
latitude: 53.5,
|
|
zoom: 6,
|
|
pitch: 0,
|
|
};
|
|
|
|
|
|
/**
|
|
* Zoom to H3 resolution mapping thresholds.
|
|
* Returns the H3 resolution to use for a given zoom level.
|
|
*/
|
|
export const ZOOM_TO_RESOLUTION_THRESHOLDS = [
|
|
{ maxZoom: 7.5, resolution: 5 },
|
|
{ maxZoom: 9.5, resolution: 6 },
|
|
{ maxZoom: 10.5, resolution: 7 },
|
|
{ maxZoom: 11.5, resolution: 8 },
|
|
{ maxZoom: 13, resolution: 9 },
|
|
{ maxZoom: Infinity, resolution: 10 },
|
|
] as const;
|
|
|
|
export const POSTCODE_ZOOM_THRESHOLD = 16;
|
|
|
|
|
|
|
|
export const FEATURE_GRADIENT: { t: number; color: [number, number, number] }[] = [
|
|
{ t: 0, color: [46, 204, 113] },
|
|
{ t: 0.33, color: [241, 196, 15] },
|
|
{ t: 0.66, color: [231, 76, 60] },
|
|
{ t: 1, color: [142, 68, 173] },
|
|
];
|
|
|
|
/** Property density gradient — light mode (cream → orange) */
|
|
export const DENSITY_GRADIENT: { t: number; color: [number, number, number] }[] = [
|
|
{ t: 0, color: [255, 255, 255] },
|
|
{ t: 0.1, color: [248, 233, 211] },
|
|
{ t: 0.5, color: [255, 221, 173] },
|
|
{ t: 0.8, color: [251, 171, 60] },
|
|
{ t: 1, color: [255, 162, 31] },
|
|
];
|
|
|
|
/** Property density gradient — dark mode (dark warm → bright amber) */
|
|
export const DENSITY_GRADIENT_DARK: { t: number; color: [number, number, number] }[] = [
|
|
{ t: 0, color: [55, 45, 35] },
|
|
{ t: 0.1, color: [85, 65, 40] },
|
|
{ t: 0.5, color: [170, 115, 50] },
|
|
{ t: 0.8, color: [230, 155, 45] },
|
|
{ t: 1, color: [255, 170, 40] },
|
|
];
|
|
|
|
/** Protomaps font glyphs URL (served locally from public/assets/) */
|
|
export const GLYPHS_URL = '/assets/fonts/{fontstack}/{range}.pbf';
|
|
|
|
/** Twemoji base URL (served locally from public/assets/) */
|
|
export const TWEMOJI_BASE = '/assets/twemoji/';
|
|
|
|
|
|
|
|
/**
|
|
* Groups whose features should be collapsed into stacked bar charts.
|
|
* Keyed by feature group name. Each entry defines one stacked chart.
|
|
*/
|
|
export const STACKED_GROUPS: Record<string, {
|
|
/** Display label for the chart */
|
|
label: string;
|
|
/** If set, use this feature's stats for the total and info popup. Otherwise sum components. */
|
|
feature?: string;
|
|
/** Suffix shown after the total value (e.g. "avg/yr") */
|
|
unit?: string;
|
|
/** Feature names that make up the segments */
|
|
components: string[];
|
|
}[]> = {
|
|
Crime: [
|
|
{
|
|
label: 'Serious crime',
|
|
feature: 'Serious crime (avg/yr)',
|
|
unit: 'avg/yr',
|
|
components: [
|
|
'Violence and sexual offences (avg/yr)',
|
|
'Robbery (avg/yr)',
|
|
'Burglary (avg/yr)',
|
|
'Possession of weapons (avg/yr)',
|
|
],
|
|
},
|
|
{
|
|
label: 'Minor crime',
|
|
feature: 'Minor crime (avg/yr)',
|
|
unit: 'avg/yr',
|
|
components: [
|
|
'Anti-social behaviour (avg/yr)',
|
|
'Criminal damage and arson (avg/yr)',
|
|
'Shoplifting (avg/yr)',
|
|
'Bicycle theft (avg/yr)',
|
|
'Theft from the person (avg/yr)',
|
|
'Other theft (avg/yr)',
|
|
'Vehicle crime (avg/yr)',
|
|
'Public order (avg/yr)',
|
|
'Drugs (avg/yr)',
|
|
'Other crime (avg/yr)',
|
|
],
|
|
},
|
|
],
|
|
Demographics: [
|
|
{
|
|
label: 'Ethnic composition',
|
|
unit: '%',
|
|
components: ['% White', '% Asian', '% Black', '% Mixed', '% Other'],
|
|
},
|
|
],
|
|
};
|
|
|
|
/**
|
|
* Groups whose enum features should be collapsed into compact multi-row charts.
|
|
* Keyed by feature group name. Each entry defines one stacked enum chart.
|
|
*/
|
|
export const STACKED_ENUM_GROUPS: Record<string, {
|
|
/** Display label for the chart */
|
|
label: string;
|
|
/** If set, use this feature for the info popup */
|
|
feature?: string;
|
|
/** Enum feature names that make up the rows */
|
|
components: string[];
|
|
/** Value order for consistent segment ordering */
|
|
valueOrder: string[];
|
|
/** Colors for each value (matches valueOrder) */
|
|
valueColors: string[];
|
|
}[]> = {
|
|
Property: [
|
|
{
|
|
label: 'Property type',
|
|
feature: 'Property type',
|
|
components: ['Property type'],
|
|
valueOrder: ['Detached', 'Semi-Detached', 'Terraced', 'Flat'],
|
|
valueColors: ['#8b5cf6', '#3b82f6', '#14b8a6', '#f59e0b'],
|
|
},
|
|
{
|
|
label: 'Leasehold/Freehold',
|
|
feature: 'Leashold/Freehold',
|
|
components: ['Leashold/Freehold'],
|
|
valueOrder: ['Freehold', 'Leasehold'],
|
|
valueColors: ['#3b82f6', '#f59e0b'],
|
|
},
|
|
],
|
|
Environment: [
|
|
{
|
|
label: 'Ground Risk',
|
|
feature: 'Environmental risk',
|
|
components: [
|
|
'Collapsible deposits risk',
|
|
'Compressible ground risk',
|
|
'Landslide risk',
|
|
'Running sand risk',
|
|
'Shrink-swell risk',
|
|
'Soluble rocks risk',
|
|
],
|
|
valueOrder: ['Low', 'Moderate', 'Significant'],
|
|
valueColors: ['#22c55e', '#eab308', '#ef4444'],
|
|
},
|
|
],
|
|
};
|
|
|
|
/** Colors for stacked bar segments */
|
|
export const SEGMENT_COLORS = [
|
|
'#ef4444', // red-500
|
|
'#f97316', // orange-500
|
|
'#eab308', // yellow-500
|
|
'#22c55e', // green-500
|
|
'#14b8a6', // teal-500
|
|
'#06b6d4', // cyan-500
|
|
'#3b82f6', // blue-500
|
|
'#8b5cf6', // violet-500
|
|
'#d946ef', // fuchsia-500
|
|
'#ec4899', // pink-500
|
|
];
|