buildTurnInstructions grouped steps purely by heading change, so a street
that bends (same name, >30° heading shift) produced redundant
'Continue/Turn onto Pine St' entries. Now consecutive legs sharing the same
street name are collapsed into a single step with summed distance.
- routing.ts: track each leg's street name and absorb subsequent same-street
steps' distance into the first; the arrival step uses the final bearing
- scripts/test.mjs: assert a bent single-named road yields 1 step, and that
two distinct streets are not merged
- osm-dump.mjs: capture way name/ref as edgeNames; honor oneway & roundabout as directed edges; graphHighways widened to include named local roads
- routing.ts: buildTurnInstructions emits 'Head north on Pine St' / 'Turn right onto 21st St'; merges short legs to avoid phantom turns; nameResolverFor() maps node path to street names
- Rebuilt tulsa-dump-graph.json: 225,956 nodes / 227,468 edges (was 55k); ~27MB (was 4.7MB)
- tests, README updated
Root cause: osm-data.mjs emitted ways with 'out center' (no geometry) as a
flat [lon,lat] labeled 'LineString'. Leaflet reads those as two invalid
points and threw 'Invalid LatLng', which aborted the entire layer load loop
in onMount -- so no layers rendered and the checkboxes all showed unchecked.
Toggling then appeared to do nothing.
Fixes:
- osm-data.mjs: coordsFor/geometryFor now emit a proper Point for any flat
[lon,lat] (from nodes / 'out center' ways) instead of a malformed LineString
- MapView.svelte: isolate each layer's load + each feature's searchable build
in try/catch so one bad feature/layer can't break all layers; skip invalid
bounds in fitBounds
- osm-data.mjs: preserve manifest entries it doesn't generate (e.g. dump
layers from osm-dump.mjs) so data/osm-dump scripts don't clobber each other
- scripts/test.mjs: add geometry-integrity checks (no malformed coords)
Verified in a real browser: all 6 layers render, each toggles off/on
independently (33361->0 overlays), and the Directions panel loads.
- scripts/osm-dump.mjs: download & stream-parse regional .osm.pbf extracts
(Geofabrik/BBBike etc). Clips to bbox, extracts POI features (poiTags),
and builds a routable road graph (coords + weighted adj) from road ways.
Caches the downloaded .pbf under scripts/.cache/ (git-ignored). Default:
Geofabrik Oklahoma extract -> tulsa-dump layer (12.8k POIs, 55k-node graph).
- src/lib/routing.ts: client-side A* routing over the graph. Snaps A/B to
nearest nodes, supports avoid-rules (category + radius, block or penalty)
built from nearby POIs; returns waypoints + distance.
- src/lib/components/DirectionsPanel.svelte: Directions UI — pick A/B by
clicking the map, choose POI categories to avoid, compute & draw the route.
- MapView: adds a Directions toggle when a dump layer with a graph is present.
- package.json: add 'build:dump'; build now runs data + dump + static.
- scripts/test.mjs: validate dump manifest entries + routing graph structure.
- README: document dump ingestion and the routing/avoid feature.
- osm-data.mjs: add 'roads' Overpass query to tulsa area — major road
classes (motorway/trunk/primary/secondary/tertiary) as LineString geometry
- MapView.svelte: render POIs that have a bearing as a rotated arrow
divIcon marker pointing in the compass heading; other POIs stay as
circleMarkers. Adds .dir-arrow CSS.
- scripts/test.mjs: adapt street-name search assertions (roads now match
address queries legitimately) and add an expectAll helper
- static/data: tulsa.geojson now includes ~20k road features (11MB)
- .gitea/workflows/ci.yml: on push/PR, runs npm ci, svelte-check, offline
regression tests, and a static (no-Overpass) build, then verifies output
- scripts/test.mjs: offline test suite — validates manifest + GeoJSON
structure and asserts fuzzy-search regressions against committed data
- package.json: add 'test' and 'build:static' scripts
- osm-data.mjs: tag OSM layers layerType='mixed' in the manifest
- 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
- src/lib/search.ts: dependency-free fuzzy search engine that matches POIs
and zones by name/address with text normalization (st->street, compass
words), substring + Levenshtein fuzzy matching, and field-aware ranking
- MapView.svelte: builds a searchable index from loaded layers, adds a
search box that shows ranked results, pans/zooms + opens popup on select,
and renders dedicated popup rows for address, Facing (compass), and
Field of view
- custom-layers.mjs: documents optional address / bearing / fov POI fields
with examples; osm-data.mjs normalizes bearing (compass point or degrees)
into degrees and carries the new properties through to GeoJSON
- README: documents POI data fields and the search feature
- scripts/custom-layers.mjs: hand-authored, self-documenting config for
custom zones (polygons) and points of interest, shipped with example
Tulsa POIs and district zones plus a copy-paste template
- osm-data.mjs: merges custom layers into static/data/custom/<id>.geojson
and includes them in the _index.json manifest with category, layerType,
and color metadata
- MapView.svelte: renders each manifest entry as an independent toggleable
Leaflet layer with per-layer styling and an on-map legend panel
- +page.svelte: loads all data sources (OSM + custom) from the manifest
- SvelteKit project with @sveltejs/adapter-static (runs fully static)
- scripts/osm-data.mjs: pulls OSM data from Overpass API and converts to
static GeoJSON under static/data/ with per-area manifest
- Leaflet map frontend that loads the static data and renders features
with popups and area selection dropdown
- npm run build fetches data then produces a self-contained static site