UI polish, bug fixes, and README

Changes since last commit:

NATS airspace
- Remove D and D_OTHER types from parser — UK small-arms ranges covered the
  entire country and made the layer unusable
- Replace title-attribute tooltips on type filters with clickable ⓘ icons
  (mobile-friendly); info text appears in a shared box below the grid
- Add Select All / Deselect All controls (moved to bottom of all layers, now
  applies to every layer checkbox not just NATS types)
- Fix per-type filter using expression syntax ['match', ...] — legacy filter
  syntax was unreliable in MapLibre GL JS 4.x

Map style switching
- Fix overlay layers being lost when switching Terrain / Satellite / Streets
  by waiting for the 'idle' event instead of 'style.load'; MapTiler styles
  fire style.load before the map is ready to accept addSource/addLayer calls
- Defensive cleanup at top of addAllLayers() removes all custom layers and
  sources before re-adding, preventing "source already exists" crashes

Location tracking
- Move locate button from floating bottom-right into the left panel
- Auto-request location on page load
- Dynamic button label: "Getting location…" → "Stop Tracking" → "Track location"
- Suppress alert on permission-denied (error code 1); show inline message for
  other errors

Panel UX
- Move planning disclaimer out of panel body into a ⚠ icon in the header;
  click to expand, includes hyperlinked NOTAM link
- Add NOTAM link to the data-links section at the bottom
- Danger / Restricted and MoD / Military rows now have ⓘ icons explaining
  that these layers have no built-in data and require a GeoJSON upload;
  removes the old "Override: load GeoJSON below" note and "(override)" labels
  from the dropdown
- Load Data section: stacked full-width layout (dropdown above button)
- Lighten grey text (#555#888, #666#999) across section labels,
  layer notes, info icons, hints, data links, and popup close button

Map bounds and attribution
- Restrict panning to UK + Channel Islands with maxBounds
- Replace default attribution control with custom one appending
  "© Bournemouth Technology" with link to bournemouthtechnology.co.uk

README
- Add full project description, feature list, tech stack table, setup
  instructions, and data source reference table
This commit is contained in:
Jon
2026-05-25 18:28:25 +01:00
parent db9d58043d
commit f741a17202
4 changed files with 297 additions and 86 deletions

View File

@@ -26,7 +26,15 @@
<div id="panel">
<div id="panel-header">
<span class="panel-title">DroneMapUK</span>
<button id="panel-toggle" title="Toggle panel"></button>
<div class="header-btns">
<button id="warn-btn" title="Planning disclaimer">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</button>
<button id="panel-toggle" title="Toggle panel"></button>
</div>
</div>
<div id="warn-popup" class="hidden">
Planning aid only. Always check <a href="https://www.aurora.nats.co.uk/" target="_blank" rel="noopener">NOTAMs</a> and official CAA sources before any flight.
</div>
<div id="panel-body">
@@ -43,16 +51,15 @@
<div id="nats-progress-fill" class="progress-fill"></div>
</div>
<div class="nats-type-grid">
<label class="type-check"><input type="checkbox" data-nats-type="R" checked><span class="tc-r">R</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="P" checked><span class="tc-r">P</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="D" checked><span class="tc-d">D</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="D_OTHER" checked><span class="tc-d">D_OTH</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="CTR" checked><span class="tc-ctr">CTR</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="CTA" checked><span class="tc-cta">CTA</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="TMA" checked><span class="tc-cta">TMA</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="RAS" checked><span class="tc-ras">RAS</span></label>
<label class="type-check"><input type="checkbox" data-nats-type="OTHER:TMZ" checked><span class="tc-tmz">TMZ</span></label>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="R" checked><span class="tc-r">R</span></label><button class="info-btn" data-info="Restricted Area — access limited by national authority"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="P" checked><span class="tc-r">P</span></label><button class="info-btn" data-info="Prohibited Area — flight permanently prohibited"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="CTR" checked><span class="tc-ctr">CTR</span></label><button class="info-btn" data-info="Control Zone — controlled airspace immediately around an aerodrome, surface to upper limit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="CTA" checked><span class="tc-cta">CTA</span></label><button class="info-btn" data-info="Control Area — larger block of controlled airspace above a minimum altitude"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="TMA" checked><span class="tc-cta">TMA</span></label><button class="info-btn" data-info="Terminal Manoeuvring Area — controlled airspace around a busy airport or cluster of airports"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="RAS" checked><span class="tc-ras">RAS</span></label><button class="info-btn" data-info="Radar Advisory Service — ATC provides traffic information and avoidance advice on request"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
<div class="type-cell"><label class="type-check"><input type="checkbox" data-nats-type="OTHER:TMZ" checked><span class="tc-tmz">TMZ</span></label><button class="info-btn" data-info="Transponder Mandatory Zone — Mode C or S transponder required when flying inside"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button></div>
</div>
<div id="nats-type-info" class="type-info-box hidden"></div>
<label class="layer-row">
<input type="checkbox" data-layer="frz" checked>
@@ -61,18 +68,24 @@
</label>
<p class="layer-note">5 km radius around licensed aerodromes (approx.)</p>
<label class="layer-row">
<input type="checkbox" data-layer="danger" checked>
<span class="dot dot-danger"></span>
<span>Danger / Restricted Areas</span>
</label>
<div class="layer-row-outer">
<label class="layer-row">
<input type="checkbox" data-layer="danger" checked>
<span class="dot dot-danger"></span>
<span>Danger / Restricted Areas</span>
</label>
<button class="info-btn" data-info="No built-in data — upload a GeoJSON file via Load Data below. Each upload replaces the previous data." data-infobox="layer-override-info"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button>
</div>
<label class="layer-row">
<input type="checkbox" data-layer="military" checked>
<span class="dot dot-military"></span>
<span>MoD / Military Areas</span>
</label>
<p class="layer-note">Override: load GeoJSON below</p>
<div class="layer-row-outer">
<label class="layer-row">
<input type="checkbox" data-layer="military" checked>
<span class="dot dot-military"></span>
<span>MoD / Military Areas</span>
</label>
<button class="info-btn" data-info="No built-in data — upload a GeoJSON file via Load Data below. Each upload replaces the previous data." data-infobox="layer-override-info"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button>
</div>
<div id="layer-override-info" class="type-info-box hidden"></div>
<!-- ── Protected nature ── -->
<div class="section-label" style="margin-top:12px">PROTECTED AREAS</div>
@@ -105,6 +118,20 @@
<span>Forestry managed land</span>
</label>
<p class="layer-note">Forestry England / FLS / NRW — load GeoJSON below</p>
<div class="type-all-row">
<button class="type-all-btn" id="layers-select-all">Select all</button>
<button class="type-all-btn" id="layers-deselect-all">Deselect all</button>
</div>
<!-- ── Location ── -->
<div class="section-label" style="margin-top:12px">LOCATION</div>
<button id="locate-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/>
<circle cx="12" cy="12" r="9" stroke-dasharray="3 3" opacity=".4"/>
</svg>
<span id="locate-label">Track location</span>
</button>
<!-- ── Map style ── -->
<div class="section-label" style="margin-top:12px">MAP STYLE</div>
@@ -132,41 +159,26 @@
<!-- ── Load data ── -->
<div class="section-label" style="margin-top:12px">LOAD DATA</div>
<p class="layer-note" style="margin-top:6px">Other GeoJSON layers:</p>
<div class="load-row">
<select id="layer-select" class="layer-select">
<option value="danger">Danger / Restricted (override)</option>
<option value="military">Military Areas (override)</option>
<option value="forestry">Forestry managed land</option>
<option value="sssi">SSSIs (Scotland / Wales)</option>
</select>
<button class="load-btn" id="geojson-btn">Load GeoJSON…</button>
</div>
<select id="layer-select" class="layer-select">
<option value="danger">Danger / Restricted</option>
<option value="military">Military Areas</option>
<option value="forestry">Forestry managed land</option>
<option value="sssi">SSSIs (Scotland / Wales)</option>
</select>
<button class="load-btn load-btn-full" id="geojson-btn">Load GeoJSON…</button>
<input type="file" id="geojson-file" accept=".geojson,.json" style="display:none">
<div class="data-links">
<a href="https://www.aurora.nats.co.uk/" target="_blank" rel="noopener">NOTAMs</a> ·
<a href="https://nats-uk.ead-it.com/cms-nats/opencms/en/uas-restriction-zones/" target="_blank" rel="noopener">NATS UAS Zones</a> ·
<a href="https://data-forestry.opendata.arcgis.com/" target="_blank" rel="noopener">Forestry England</a> ·
<a href="https://www.arcgis.com/apps/webappviewer/index.html?id=e4b9f5f437474e0481a3cec097e4c2ec" target="_blank" rel="noopener">FLS Scotland</a> ·
<a href="https://datamap.gov.wales/" target="_blank" rel="noopener">NRW Wales</a> ·
<a href="https://naturalengland-defra.opendata.arcgis.com/" target="_blank" rel="noopener">Natural England</a>
</div>
<div class="disclaimer">
⚠ Planning aid only. Always check NOTAMs and official CAA sources before any flight.
</div>
</div>
</div>
<!-- Locate button -->
<button id="locate-btn" title="Track my location">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/>
<circle cx="12" cy="12" r="9" stroke-dasharray="3 3" opacity=".4"/>
</svg>
</button>
<!-- Click info popup -->
<div id="popup" class="hidden">
<button id="popup-close"></button>