hermes-explorigin 4e3fef6559 Add path/route layer type + online geocoding + Rogers County example data
- custom-layers.mjs: new 'path' layerType (LineStrings like GPX tracks/trails)
  with a 'line' feature format, an example trails layer, and a seeded
  Rogers County POI layer with real geocoded coordinates (museums, courthouse,
  university, towns)
- osm-data.mjs: converts path features to GeoJSON LineStrings and tags
  layerType='path' in the manifest; fixes kind detection for all three types
- MapView.svelte: styles path layers as dashed polylines, computes bounds for
  LineStrings, supports 'path' in search results, and adds a Nominatim
  'Places (online)' geocoding fallback section to the search box (debounced,
  fit-to-bounds on select)
- geocode.ts: dependency-free Nominatim client
- README: documents path layers and online location search
2026-08-08 18:26:48 +00:00

Navigator

A custom web application that serves OpenStreetMap (OSM) data. It has a build process that:

  1. Pulls OSM data from the Overpass API for configurable geographic areas and feature types.
  2. Merges hand-authored custom layers — zones (polygons) and points of interest — from scripts/custom-layers.mjs.
  3. Converts everything to static GeoJSON files.
  4. Builds a SvelteKit frontend (with the static adapter) into a plain static site that renders each data source as a toggleable layer on an interactive Leaflet map.

The final output in build/ is a fully self-contained static site — no server runtime required. You can serve it with any static HTTP server (nginx, Apache, python -m http.server, S3/Cloudflare Pages, etc.).

Built With

Quick Start

npm install

# Fetch & convert OSM data into static/data/*.geojson
npm run build:data

# Full production build: (fetch data) + (static site) -> build/
npm run build

# Preview the production build locally
npm run preview

Development

npm run dev         # Vite dev server (your data in static/data is served too)
npm run check       # Type + Svelte checks

Build Process

Command What it does
npm run build:data Runs scripts/osm-data.mjs to fetch OSM data → static/data/
npm run build build:data followed by the SvelteKit static build → build/
npm run preview Serves the build/ output locally

Data layout

static/data/
├── _index.json              # Manifest of all built layers (drives the UI)
├── <area>.geojson           # One FeatureCollection per Overpass area
└── custom/
    └── <layer>.geojson      # One FeatureCollection per custom zone/POI layer

The frontend loads /data/_index.json, then fetches each layer's GeoJSON and renders it as a toggleable overlay with a legend (top-right). Every layer can be shown/hidden independently.

Configuring Areas & Queries

Edit scripts/osm-data.mjs — the AREAS object describes each area:

  • bbox[south, west, north, east] in decimal degrees.
  • queries — a map of name → Overpass QL snippet. Use {{bbox}} as the placeholder for the area's bounding box.
  • The script falls back across multiple public Overpass mirrors if one is overloaded, and is polite to the API (short delay between queries).

Example:

parks: `
  way["leisure"="park"]({{bbox}});
  out center tags geom;
`

List configured queries with npm run data -- --queries, or build a single area with npm run data -- --area=tulsa.

Custom Layers (Zones, Points of Interest & Paths)

Besides Overpass-fetched data, you can define your own layers by hand in scripts/custom-layers.mjs. It ships with several example layers (my-places POIs, districts zones, trails path, and rogers-county local POIs) that you can extend or replace.

Each layer has:

  • id — unique slug (becomes the output filename)
  • name — label shown in the UI legend
  • layerType'poi' (point), 'zone' (polygon), or 'path' (LineString)
  • color — hex color used for markers/fill/lines
  • features — array of feature objects

POI (point) — optional address, bearing, and fov fields:

{
  name: 'Gathering Place',
  desc: 'Riverside park',
  address: '2650 S John Williams Way E, Tulsa, OK 74114',
  bearing: 'SE',   // compass point (N, NNE, NE, ...) OR numeric degrees (0-360)
  fov: 140,        // field of view in degrees (optional)
  lon: -95.9791,
  lat: 36.1098
}
  • address — street address shown in the popup
  • bearing — compass direction the POI faces; accepts a compass point ('N', 'NNE', 'NE', ...) or a numeric bearing in degrees
  • fov — field of view in degrees

The popup renders these as dedicated rows (Facing / Field of view).

Zone (polygon — the ring is closed for you):

{
  name: 'Downtown Tulsa',
  desc: 'Rough downtown core',
  polygon: [
    [-96.0000, 36.1300],
    [-95.9900, 36.1300],
    [-95.9900, 36.1600],
    [-96.0000, 36.1600]
  ]
}

Path / route (LineString — an ordered list of points like a GPX track):

{
  name: 'Claremore Lake Loop',
  desc: 'Example walking route around the lake',
  line: [
    [-95.5649, 36.3415],
    [-95.5700, 36.3430],
    [-95.5750, 36.3420],
    [-95.5720, 36.3360]
  ]
}

Paths render as dashed polylines and are searchable by name.

Coordinates are [longitude, latitude] (lon first, like GeoJSON). The file also includes a copy-paste TEMPLATE block for adding new layers. After editing, run npm run build:data (or npm run build) to regenerate the static data.

The webapp includes a fuzzy search in the top bar. It matches your POIs, zones, and paths by name or address — and, as a fallback, queries the Nominatim OSM geocoder so you can also search for any location by name (cities, landmarks, addresses anywhere). A "Places (online)" section appears beneath the local matches; selecting a result pans/zooms the map to it (fit-to-bounds for places with a bounding box).

The matcher:

  • Normalizes text (case, punctuation, and common address words — ststreet, rdroad, aveavenue, nnorth, etc.), so abbreviated or partial addresses resolve correctly.
  • Uses substring + Levenshtein edit-distance tolerance, so typos and near- matches still hit (e.g. philbrick finds Philbrook).
  • Ranks name matches above address matches above description matches.

Deployment

The build/ directory is entirely static. Serve it directly:

cd build
python3 -m http.server 8080
# or: nginx -s  listen 8080; root /path/to/build;  (with a fallback to index.html)

Because the site uses a static adapter with prerendering, everything can be hosted on any static file host or CDN.

Repository

Hosted on Gitea: https://gitea.thecookiejar.me/hermes-explorigin/navigator

Description
Software project repository
Readme 14 MiB
Languages
Svelte 41.3%
JavaScript 30%
TypeScript 28.5%
HTML 0.2%