Skip to content

@studnicky/geo-layer-voting-district

US congressional/voting-district geohash lookup layer, built from US Census TIGERweb voting-district boundaries.

This package resolves a WGS-84 coordinate to its US congressional (voting) district name in O(1), decoding a compact geohash-4 cell table with an override tree for boundary cells. VotingDistrictBuilder builds that artifact from TIGERweb data (or any compatible adapter); VotingDistrictLookup decodes it and answers lookup(lat, lon) queries. TIGER is a US-only publisher, so coverage is US-only — every non-US coordinate resolves to null.

Install

bash
pnpm add @studnicky/geo-layer-voting-district

Requires @studnicky:registry=https://npm.pkg.github.com in .npmrc.

Lookup against the bundled fixture

VotingDistrictLookup.default() loads a synthetic placeholder fixture (three fake latitude-banded districts) — it proves the decode/lookup path end to end and fires onPlaceholderWarning since metadata.synthetic is true:

ts
import { VotingDistrictLookup } from '../src/index.js';

function demonstrateLookupBundledFixture(): { 'equatorResult': string | null; 'northResult': string | null; 'sourceId': string; 'southResult': string | null; 'synthetic': boolean; 'uncoveredResult': string | null; 'warningCount': number } {
  // This layer only covers the US — TIGER is a US-only publisher.
  console.log('coverage:', VotingDistrictLookup.coverage);

  const warnings: string[] = [];

  function collectWarning(message: string): void {
    warnings.push(message);
  }

  // .default() loads the bundled synthetic fixture — no network access required.
  // It warns via onPlaceholderWarning since the fixture isn't real district data.
  const lookup = VotingDistrictLookup.default({ 'onPlaceholderWarning': collectWarning });

  console.log('placeholder warning:', warnings[0]);
  console.log('metadata.synthetic:', lookup.metadata.synthetic);
  console.log('metadata.sourceId:', lookup.metadata.sourceId);

  // The bundled fixture has three latitude-banded districts.
  const northResult = lookup.lookup(60, 0);
  const equatorResult = lookup.lookup(0, 0);
  const southResult = lookup.lookup(-60, 0);
  console.log('lookup(60, 0):', northResult);
  console.log('lookup(0, 0):', equatorResult);
  console.log('lookup(-60, 0):', southResult);

  // A coordinate outside every mapped district resolves to null.
  const uncoveredResult = lookup.lookup(0, 179);
  console.log('lookup(0, 179):', uncoveredResult);

  return {
    'equatorResult':   equatorResult,
    'northResult':      northResult,
    'sourceId':         lookup.metadata.sourceId,
    'southResult':      southResult,
    'synthetic':        lookup.metadata.synthetic,
    'uncoveredResult':  uncoveredResult,
    'warningCount':     warnings.length
  };
}

Building from an adapter

VotingDistrictBuilder.build() builds a production-accurate table against a TIGERweb-compatible adapter, then VotingDistrictLookup.fromArtifact() loads the result:

ts
import { VotingDistrictBuilder, VotingDistrictLookup } from '../src/index.js';

async function demonstrateBuildAndLookup(): Promise<{ 'cellTableBinPath': string; 'districtName': string; 'insideResult': string | null; 'mixedCellCount': number; 'outsideResult': string | null; 'tupleCount': number }> {
  const districtName = 'Example Congressional District';
  const bbox: [number, number, number, number] = [-170, -80, 170, 80];

  const feature: Feature = {
    'geometry': {
      'coordinates': [[[-170, -80], [170, -80], [170, 80], [-170, 80], [-170, -80]]],
      'type': 'Polygon'
    },
    'properties': { 'NAME': districtName },
    'type': 'Feature'
  };
  const featureCollection: FeatureCollection = { 'features': [feature], 'type': 'FeatureCollection' };

  // A minimal in-memory adapter — real callers use `USCensusTigerAdapter` from
  // `@studnicky/geo-adapters` to fetch live TIGERweb data instead.
  class ExampleAdapter implements AdministrativeSystemAdapterInterface<FeatureCollection> {
    readonly coverage: readonly string[] = ['US'];
    readonly layers: readonly AdminLayerType[] = ['voting-district'];
    readonly systemId: string = 'example-voting-district';

    fetchLayer(_layer: AdminLayerType, _parameters: FetchParametersType): Promise<RawDatasetType<FeatureCollection>> {
      const rawDataset: RawDatasetType<FeatureCollection> = {
        'data': featureCollection,
        'fetchedAt': new Date(0).toISOString(),
        'license': 'example — not for production use',
        'sourceId': 'example-voting-district'
      };
      return Promise.resolve(rawDataset);
    }
  }

  const outputDir = mkdtempSync(join(tmpdir(), 'geo-layer-voting-district-example-'));

  try {
    const buildResult = await VotingDistrictBuilder.build({
      'adapter': new ExampleAdapter(),
      'bbox': bbox,
      'maxDescentDepth': 2,
      'outputDir': outputDir
    });

    console.log('tupleCount:', buildResult.tupleCount);
    console.log('mixedCellCount:', buildResult.mixedCellCount);
    console.log('cellTableBinPath:', buildResult.cellTableBinPath);

    const lookup = VotingDistrictLookup.fromArtifact(buildResult.artifact);

    const insideResult = lookup.lookup(0, 0);
    const outsideResult = lookup.lookup(0, 179);
    console.log('lookup(0, 0):', insideResult);
    console.log('lookup(0, 179):', outsideResult);

    return {
      'cellTableBinPath': buildResult.cellTableBinPath,
      'districtName':     districtName,
      'insideResult':     insideResult,
      'mixedCellCount':   buildResult.mixedCellCount,
      'outsideResult':    outsideResult,
      'tupleCount':       buildResult.tupleCount
    };
  }
  finally {
    rmSync(outputDir, { 'force': true, 'recursive': true });
  }
}

Source on GitHub