2 Commits

Author SHA1 Message Date
631b316118 Adjust a measured circle's radius from its tooltip, in ground metres
Officers asked to enter an exact distance rather than drag for it. The tooltip
that appears when the second click lands now carries the adjustment: minus, the
figure itself, plus. Tapping the figure swaps in a numeric input, so an exact
radius can be typed; inputmode="decimal" brings up a keypad rather than a full
keyboard on a phone.

Not a dial. A radius runs from a few metres to several kilometres and no dial
gives usable resolution across that range on a tooltip this size. Stepping snaps
to an increment that grows with the value — 1 m below 50, 5 m below 200, 10 m
below 1 km, 50 m below 5 km — so one tap means something at either end, and
repeated taps land on round numbers instead of carrying the fraction the drag
happened to finish on.

Everything writes through MapTools.setCircleRadius(). Measurements were made
read-only earlier precisely because a draggable handle moved the geometry while
the popup went on reporting the radius captured at draw time; a single path
means the geometry, the radius line, the tooltip and the analysis popup cannot
drift apart again.

The figures are now ground distances. The geometry stores a Web Mercator radius,
which overstates the ground by 1/cos(latitude) — a 200 m circle at Wa was 197 m
on the ground. That was invisible while dragging, because the label and the
shape agreed with each other, but typing 200 is a claim about the ground. The
conversion lives in units.js and is applied in the live tooltip, the adjuster
and the Circle Analysis popup, so all three state the same distance.

Two deliberate choices worth knowing before the usability check:

  - The tooltip is frozen where the draw finished. It is anchored to the
    circumference, so re-positioning on every change would slide the buttons out
    from under the officer's thumb. A large adjustment therefore leaves it
    sitting inside the circle rather than on its edge.
  - No measure-complete event fires on adjustment. Consumers read that as "a new
    measurement was drawn", and stepping would emit a stream of false ones.

The overlay is created with stopEvent:false so the map keeps working through the
label; the buttons stop their own events, or a tap would also pan the map.

Service Worker version deliberately unchanged, so reverting does not leave
clients on a newer cache than main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 17:06:14 +02:00
ef12e4477b Offline tile cache, polygon Divide, topographic layer integrations
Major feature batch covering drawing-tool improvements, layer additions,
and offline-first capabilities. Largest changes in MapView.js (+1700),
main.js (+1500), public/sw.js (+367), and new modules under src/.

Drawing & editing toolkit
  * Polygon Divide tool — sub-button under Split, divides a polygon into
    N equal-area pieces via binary search; user picks the cutting edge
  * UPN pick phase after Split and Divide — non-picked pieces have their
    identifier fields cleared automatically
  * Improved Merge algorithm — vertex-to-edge proximity (5 m tol.) with
    hybrid lockstep extension; bold A/B labels on selected polygons
  * Persistent vertex highlights — all vertices of the selected polygon
    rendered as dots while edit mode is on, without subclassing ol-ext
  * Toast notifications for merge/split/divide outcomes
  * Shapefile import — addGeoJSONLayer now includes an image style so
    Point features render (previously invisible)

Background & overlay layers
  * DEAfrica Coastlines v0.4 (WMS) in Biophysical Environment
  * DEAfrica Slope (SRTM 30m, style_slope) — semi-transparent background
  * Contours hillshade — get_contours_hillshade.php → local SQLite cache
  * OSM_roads — get_osm_roads.php → local SQLite cache, casing-stroke
    style (black 3.5 px outer, #F0F1F0 1.5 px inner)
  * External Source dialog — green + button in LayerSwitcher lets users
    add WMS / WFS / XYZ layers at runtime
  * Generic addWMSLayer / addXYZLayer with style, opacity, zIndex,
    legendUrl, onlineOnly options
  * TileWMS replaces ImageWMS (fixes 'Width exceeds 512' WMS errors)
  * Legend panel — bottom-right, auto-shown for visible layers that
    register a legendUrl
  * Default base map setting in Settings, persisted in localStorage;
    setBaseMap() on MapView

Offline tile cache (Phase 1 + 2)
  * Service worker: per-host tile caches (osm / topo / satellite /
    carto-light / carto-dark), counter-based eviction to prevent
    iOS Safari memory-pressure reloads, GET_TILE_STATS /
    CLEAR_TILE_CACHES message API
  * pwa.js helpers: getActiveServiceWorker, onServiceWorkerControllerChange,
    getTileCacheStats, clearTileCaches, getStorageEstimate
  * Settings: Offline Map Tiles card with per-provider stats + clear
  * Phase 2 download dialog: form to pick base map, area (current view /
    district / Ghana), zoom range; live tile-count + size estimate;
    progress bar with cancel; OfflineTileDownloader class with
    concurrency + throttling

Local database management
  * osm_roads table + saveOSMRoads / getLocalOSMRoads helpers
  * CACHED_LAYER_TABLES allow-list with clearTable / clearAllCachedLayers
  * Local Database Tables card: per-row Clear button (cached layers
    only) + 'Refresh cached layers' header button with reload prompt

Build & infrastructure
  * Shpjs lazy-loaded via dynamic import (saves ~140 kB from initial JS)
  * chunkSizeWarningLimit raised to 900 kB (openlayers + sqlite3.wasm
    can't be split further)
  * Toast notification module (src/toast.js)
  * Units module (src/units.js) for metric / imperial conversions
  * PDF export module (src/pdf-export.js)

Documentation & SQL
  * Topographic_Background_Layers_for_LUPMIS2.docx — research report
  * OpenTopography_Workflow.svg/.png — ETL pipeline diagram
  * LUPMIS2_Development_Status_Report.docx — April update section
  * sql/create_landuse_parcels.sql — PostgreSQL schema for the LUSPA
    land-use parcel specification (Feb 2026, revised), with PostGIS
    geometry column and standard indices

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 10:55:30 +02:00