Architecture - msupino/NavigationApp GitHub Wiki
๐ฎ๐ฑ ืขืืจืืช
NavAid is plain HTML / CSS / JavaScript on top of Leaflet. No build step, no bundler, no transpiler. What ships in docs/ is exactly what runs.
See Directory Structure for the current docs/ tree. In short: runtime source lives in docs/app/, datasets in docs/data/, locale bundles in docs/i18n/, browser images in docs/assets/, and legacy static-map files in docs/legacy/.
<script> tags in index.html load in this exact order โ there are no imports:
i18n/<lang>/strings.js
โโโ sets window.S = { โฆ } for i18n
app/core.js
โโโ window.NavAid namespace, map = L.map(...), tuning registry, helpers
app/route-graph-shapes.js
โโโ projects nav waypoints / leg altitudes / comm-change points out of the layer graph
app/terrain.js
โโโ terrain grid + MSA (minimum safe altitude) helpers
app/draw.js
โโโ draw(), scheduleDraw() (rAF-coalesced)
app/interact.js
โโโ canvas overlay event handlers, hit-test, drag
app/io.js
โโโ save/load, exportPNG, flight plan, KML
app/alt-pair-directions.js
โโโ altitude-pair direction helpers
app/gdrive.js
โโโ optional Google Drive route library
app/gps.js
โโโ live position, track recording, in-flight alerts, compass fallback
app/ui.js
โโโ toolbar wiring, layer picker, rotate dial, map controls, bootstrap
app/editor.js
โโโ the ?editor=1 map-data editor
app/assistant.js
โโโ the AI assistant panel (off unless featureAssistant is on)
app/offline-tiles.js
โโโ downloadable offline chart packs
Each module attaches its public surface to window.NavAid or relies on a globally-defined function from a previous module. There is no module system.
A single global namespace window.NavAid plus a few module-local variables. The core state shape:
{
waypoints: [{ lat, lng, name }],
legs: [{ inboundAltitude, outboundAltitude, flightSpeed,
inLabel: { a, p }, outLabel: { a, p } }],
notes: [{ lat, lng, text, color, shape }]
}The number of legs is always max(0, waypoints.length - 1).
Rendering happens on a <canvas id="overlay"> positioned over the Leaflet map. Leaflet handles tiles + zoom/pan; NavAid draws everything else.
Each draw() call:
- Resize the canvas to match map size.
- Clear.
- Project all positions via
map.latLngToContainerPoint(...)to current pixel coords. - Paint the core route elements in this simplified order (back to front):
- Navigation waypoints (if toggle on).
- Airfields (if toggle on).
- Legs (line, arrow, mid-leg distance badge, return arrow if toggle on, halo if highlight-diff).
- Waypoints (circle + name / number).
- Notes (background, then text).
- Page frame (dashed rectangle if A3/A4 active).
- Persist state if not exporting.
This list is intentionally abridged. draw() in docs/app/draw.js is the
authority for terrain, areas, rings, VOR/NOTAM overlays, kites, tracks,
own-ship, information, the plan card, and their complete paint order.
draw() is wrapped by scheduleDraw() which collapses multiple calls into a single requestAnimationFrame, avoiding redraw churn during pan/zoom/rotate.
interact.js generally mirrors paint priority in reverse so the topmost
element wins. Click coordinates are converted to map container pixels; each
element type has a hit* function. The simplified core route order is:
hitNote -> hitWaypoint -> hitLegLabel -> hitLeg -> hitPageFrame
This matches the paint order so overlapping notes remain selectable above waypoints.
interact.js is the authority for the additional comm callout, overlay marker,
NOTAM/bubble, cumulative-kite, and selected-item priority paths.
Via the leaflet-rotate plugin. The dial is a custom DOM control next to Leaflet's zoom buttons. The rotate event triggers refreshDial() + scheduleDraw() and persists map.getBearing() to localStorage (suppressed during export).
Implemented in io.js:
- Snapshot the current page-frame geometry.
- Choose the target tile zoom: highest native zoom that keeps the rotated bounding box โค 10 000 ร 10 000 px.
- Build a tile grid covering the rotated frame.
- Clip flight-maps.com tile requests to published chart bounds and fetch each tile (direct for OSM / Esri; via the
navaid-tiles.supino.orgexport mirror for the chart layers). HTTP 404 tiles are expected blanks and are skipped. - Composite tiles onto an offscreen canvas, honoring the Map opacity slider.
- Project + draw the overlay on top, including Navigation Waypoints and Airfields when enabled.
- Convert to a Blob, unlock map interaction, and trigger download.
See Service Worker.
See Bilingual UI. At the DOM level: data-i18n="key" / data-i18n-title="key" / data-i18n-placeholder="key" attributes read from window.S. There is no MessageFormat / ICU; just string lookups.
No build. The docs/ folder is the artifact. A GitHub Actions workflow assembles main/docs/ -> / and dev/docs/ -> /staging/, rewrites ?v= and NavAid.version to the branch short SHA, and publishes to GitHub Pages. See Deployment.