@studnicky/geo-layer-state
Geohash-indexed state/province lookup: resolves a WGS-84 coordinate to its containing admin-1 region name via a bit-packed cell table with adaptive-depth boundary overrides.
This package resolves a (lat, lon) coordinate to the name of its containing Natural Earth admin-1 region (state, province, etc.), or null outside every mapped feature. Cell classification, adaptive-depth override descent, and artifact encoding are delegated to @studnicky/geo-boundary-layer-kit; this package supplies only the admin-1-specific NamedFeatureResolver oracle (properties.name extraction from Natural Earth GeoJSON) that the kit builds and looks up against.
Install
pnpm add @studnicky/geo-layer-stateRequires @studnicky:registry=https://npm.pkg.github.com in .npmrc.
Lookup against the bundled fixture
StateLookup.default() loads a bundled synthetic fixture artifact for development and testing:
import { StateLookup } from '../src/index.js';
function demonstrateLookupDefault(): { 'alpha': string | null; 'beta': string | null; 'outside': string | null; 'synthetic': boolean; 'warningCount': number } {
const warnings: string[] = [];
function collectWarning(message: string): void {
warnings.push(message);
}
const lookup = StateLookup.default({ 'onPlaceholderWarning': collectWarning });
// lookup resolves a WGS-84 coordinate to its containing state/province name
const alpha = lookup.lookup(2.5, 2.5);
const beta = lookup.lookup(2.5, 7.5);
console.log('point inside Alpha:', alpha);
console.log('point inside Beta:', beta);
// a point outside every feature resolves to null
const outside = lookup.lookup(-70, -70);
console.log('point outside every feature:', outside);
// the bundled default artifact is a synthetic fixture, so default() warns once
console.log('placeholder warning:', warnings[0]);
// .metadata exposes the artifact's provenance
console.log('metadata.synthetic:', lookup.metadata.synthetic);
return { 'alpha': alpha, 'beta': beta, 'outside': outside, 'synthetic': lookup.metadata.synthetic, 'warningCount': warnings.length };
}Building from a FeatureCollection
StateBuilder.build() builds a real artifact from a Natural Earth admin-1 FeatureCollection, then BoundaryLayerLookup.fromArtifact() loads it for lookups:
import { BoundaryLayerLookup, StateBuilder } from '../src/index.js';
async function demonstrateBuildAndLookup(): Promise<{ 'doverland': string | null; 'mixedCellCount': number; 'ricoland': string | null }> {
// a tiny 2-state admin-1 FeatureCollection, standing in for a real Natural Earth fetch
const featureCollection: FeatureCollection = {
'features': [
{ 'geometry': { 'coordinates': [[[0, 0], [5, 0], [5, 5], [0, 5], [0, 0]]], 'type': 'Polygon' }, 'properties': { 'name': 'Ricoland' }, 'type': 'Feature' },
{ 'geometry': { 'coordinates': [[[5, 0], [10, 0], [10, 5], [5, 5], [5, 0]]], 'type': 'Polygon' }, 'properties': { 'name': 'Doverland' }, 'type': 'Feature' }
],
'type': 'FeatureCollection'
};
const fakeFetch: typeof fetch = () => {
const response = new Response(JSON.stringify(featureCollection), { 'status': 200 });
return Promise.resolve(response);
};
// StateBuilder.build fetches admin-1 via the injected adapter and encodes a cell table + override tree
const adapter = NaturalEarthAdapter.create(fakeFetch);
const result = await StateBuilder.build({ 'adapter': adapter, 'maxDescentDepth': 2 });
console.log('mixed cell count:', result.mixedCellCount);
// BoundaryLayerLookup.fromArtifact decodes the built artifact for lookups, without the placeholder-warning check StateLookup.default performs
const lookup = BoundaryLayerLookup.fromArtifact(result.artifact);
const ricoland = lookup.lookup(2.5, 2.5);
const doverland = lookup.lookup(2.5, 7.5);
console.log('point inside Ricoland:', ricoland);
console.log('point inside Doverland:', doverland);
return { 'doverland': doverland, 'mixedCellCount': result.mixedCellCount, 'ricoland': ricoland };
}