2026-06-29 13:57:40 -05:00
2026-06-26 11:23:09 -05:00
2026-06-29 13:57:40 -05:00
2026-06-26 15:48:12 -05:00
2026-06-26 15:48:12 -05:00
2026-06-26 11:23:09 -05:00
2026-06-26 15:48:12 -05:00
2026-06-26 11:23:09 -05:00
2026-06-26 15:48:12 -05:00
2026-06-26 15:48:12 -05:00

Yard Map

Static yard mapping site built with Leaflet and plain browser modules.

Status

The project currently has:

  • A static Leaflet map with OSM raster tiles.
  • Client-side JavaScript-authored yard geometry converted to GeoJSON at load time.
  • Typed feature classes with centralized styling.
  • Schema-versioned yard data with a top-level feature type catalog.
  • Per-anchor local coordinate rotation for offset-based authoring.
  • Feature relationship metadata (id, parentId, groupIds) and a top-level group catalog for future visibility controls.
  • Example yard data mostly copied from buildings.gpkg and then preserved as JS modules.

The next likely product direction is map-layer visibility controls driven by the existing feature groups and parent-child relationships.

Authoring model

Geometry stays in JavaScript, then gets converted to GeoJSON client-side at load time.

  • Use absolute coordinates with point(lat, lon).
  • Use absolute GeoJSON-style coordinates with lngLat(lon, lat) or .trace([[lon, lat], ...]).
  • Use local offsets with offset(origin) inside .add(...), for example .add(offset(lotCorner), south(ft(15)), east(ft(10))).
  • Build typed features with classes like new House(), new Garage(), new Tree(), and new Sprinkler() so styles live in one place.
  • Add relationships with .childOf(...) and .inGroup(...) so future UI can show or hide related features together.

The example yard is now split by concern:

  • src/data/boundaries.js
  • src/data/buildings.js
  • src/data/pavement.js
  • src/data/plants.js
  • src/data/irrigation.js

The typed feature registry lives in src/lib/feature-types.js, feature classes live in src/lib/yard-features.js, and shared coordinate helpers live in src/lib/geometry.js. Feature type definitions include the label, required geometry type, known detail fields, and default Leaflet style.

Local north, south, east, and west offsets are rotated per anchor. In this example, topLeftLotCorner in src/data/anchors.js carries assumedNorthClockwiseDegrees from src/data/settings.js. A negative value means that anchor's local north is counterclockwise from true north, so local east drifts a bit toward true north.

Most example geometry was copied from buildings.gpkg and preserved as JS-authored coordinates. Tree records also carry custom attributes like canopy diameter, height, and planted date for popup rendering.

Feature relationships are exported with each GeoJSON feature as stable id, parentId, and groupIds properties. Each feature also exports universal startDate and endDate lifecycle fields for future time-slider filtering. The collection exposes schemaVersion, lifecycleFields, featureTypes, and groups at the top level. Style is resolved from the feature type registry at render time rather than stored on each exported feature. The current sample marks the porch and deck as part of the house and groups the Medora junipers under Juniper Trees.

Project structure

  • src/lib/geometry.js: low-level coordinate and offset helpers.
  • src/lib/feature-types.js: centralized default styling by feature kind.
  • src/lib/yard-features.js: typed feature classes, feature/group metadata, and GeoJSON export.
  • src/data/settings.js: local authoring settings such as lot rotation.
  • src/data/anchors.js: named anchor points for offset-based authoring.
  • src/data/boundaries.js: lot boundary and fence features.
  • src/data/buildings.js: house, garage, porch, deck, and building-related groups.
  • src/data/pavement.js: driveway and walkway geometry.
  • src/data/plants.js: flower beds, trees, and tree groups.
  • src/data/irrigation.js: sprinkler features.
  • src/data/yard.js: top-level yard collection assembly.
  • src/main.js: Leaflet rendering, legend generation, and popup rendering.

Key decisions

  • Geometry is authored in JavaScript, not GeoJSON, so yard data can mix exact coordinates with local offset expressions.
  • Styling is defined by feature type rather than repeated inline for each feature.
  • Local offsets rotate per anchor, not globally, so future anchors can carry different orientations.
  • Grouping is stored in the data model now so later show/hide behavior can be implemented without restructuring features.
  • The example GPKG data was used as a one-time source to seed JS-authored geometry, not as a runtime dependency.

GeoPackage notes

  • buildings.gpkg was used to seed most sample geometry.
  • The lot_boundary layer had mixed or incorrect CRS metadata.
  • The usable lot polygon was fid = 2, and it had to be treated as EPSG:26914 during one-time extraction before converting to JS coordinates.

Validation

Useful local checks:

node -e "import('./src/data/yard.js').then(({ yardGeoJSON }) => console.log(yardGeoJSON.features.length))"
python3 -m http.server 4173

The first check validates that the authored yard data still imports and exports cleanly. The second runs the static site locally.

Run locally

Because the app uses ES modules, serve it over HTTP instead of opening index.html directly.

python3 -m http.server 4173

Then open http://localhost:4173.

Zoom behavior

The yard overlays are vector data, so they stay sharp at any zoom level the map allows. The current basemap is still raster OSM tiles, so above zoom 19 Leaflet reuses and scales those tiles instead of fetching higher-resolution imagery.

If you want a truly crisp basemap at arbitrary close zoom, you need a vector tile or self-hosted tile source rather than the standard public OSM raster tile endpoint.

Future direction

  • Add UI controls for toggling groups and possibly parent-linked feature clusters.
  • Decide whether toggles should operate on feature groups, feature kinds, parent-child trees, or all three.
  • If sharper basemap zoom is needed, replace the raster OSM background with a vector tile or self-hosted tile solution.
  • If more data import is needed from GIS sources, prefer one-time extraction into JS-authored modules rather than making the app depend on runtime GIS tooling.
S
Description
No description provided
Readme
4.1 MiB
Languages
JavaScript 88.4%
CSS 8.9%
HTML 1.8%
Shell 0.9%