mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 23:16:46 +00:00
c83eb42730
RUN-01. Run joins the tour types in the planner, with Running as its first profile, chosen on purpose like a bike tour's. A run is routed on foot for runnable, mostly paved ways: tracks and ferries only where there is no other way (use_tracks 0, use_ferry 0, measured against the public Valhalla), no hiking limit and no via ferrata. The runner types a pace in min/km; the running time is the distance at that pace and nothing else, shown under the field as badges (8 km x 6:00 /km = 48 min). TREK suggests no pace: without one the time stays unknown and Save waits, text that is no pace or a pace outside 2:00 to 20:00 is marked. The info dot, the overview and the head say climbs, descents and difficulty are not in the time, and the time reads as planned everywhere, so it never passes for a recorded one; the heights are shown as for any tour on land. Type, profile, pace and route come back on opening, survive a draft reload, an undo of the type, a copy and a take-over; switching to another type drops profile and pace. Day assignment, the 3D terrain view (with topo and satellite, no ferratas) and a routing failure keeping the last route work as for every tour. A GPX file can be imported as a run with its profile and no pace, and planned over as a run. Runs export to GPX as running and get their own places along the way (water, toilets, parks, viewpoints). The server keeps tours.run_profile (CHECK list, already holding trail for RUN-02, since SQLite cannot widen a CHECK in place) and tours.run_pace_seconds_per_km (120 to 1200), switches the run type on, refuses a run without a profile and run fields on any other type, and list_tours names both with what the planned time does not include.
80 lines
3.9 KiB
TypeScript
80 lines
3.9 KiB
TypeScript
import type { TourTypeKey } from '@trek/shared';
|
|
import type { TourBaseLayer } from '../Map/MapLayerSwitcher';
|
|
|
|
/**
|
|
* P2B-06: which maps the tour planner offers for each tour type. The planner
|
|
* reads this one table; the global map setting is never touched, and a choice
|
|
* made here lasts only as long as the planner keeps it.
|
|
*
|
|
* A base layer is the map itself (one at a time). An overlay is information
|
|
* laid over it and switched on its own; it is off until the user turns it on.
|
|
* Only sources TREK already ships or that a card cleared are listed: OpenTopoMap
|
|
* and the Esri imagery the planner had, OpenHikingMap (MAP-01), the via ferrata
|
|
* layer (RC-10) and OpenSeaMap's seamarks (PAD-10).
|
|
*
|
|
* - Hike: the standard map first, as before; topo, OpenHikingMap (MAP-01, while the admin
|
|
* allows it) and satellite beside it; via ferratas.
|
|
* - Bike (BIK-01): the standard map, topo for the climbs, CyclOSM (BIK-06, while the admin
|
|
* allows it) and satellite. No ferratas, a bike tour climbs none.
|
|
* - Run (RUN-01): the standard map, topo for the climbs and satellite. No ferratas, a run
|
|
* takes none.
|
|
* - Paddle: the standard map, whose water reads clearly, and satellite. No topo and
|
|
* no ferratas, those are hiking maps. Seamarks as an overlay.
|
|
* - Any other type (switched off, or one this build does not plan): the standard map
|
|
* and satellite, no overlays.
|
|
*
|
|
* If an overlay fails, the base map and the planning go on; the switch says so.
|
|
*/
|
|
type TourOverlayId = 'ferratas' | 'seamarks';
|
|
|
|
export interface TourMapLayerSet {
|
|
bases: readonly TourBaseLayer[];
|
|
defaultBase: TourBaseLayer;
|
|
overlays: readonly TourOverlayId[];
|
|
}
|
|
|
|
const HIKE: TourMapLayerSet = {
|
|
bases: ['default', 'topo', 'satellite'],
|
|
defaultBase: 'default',
|
|
overlays: ['ferratas'],
|
|
};
|
|
const HIKE_WITH_HIKING_MAP: TourMapLayerSet = { ...HIKE, bases: ['default', 'topo', 'hiking', 'satellite'] };
|
|
const BIKE: TourMapLayerSet = { bases: ['default', 'topo', 'satellite'], defaultBase: 'default', overlays: [] };
|
|
const BIKE_WITH_CYCLE_MAP: TourMapLayerSet = { ...BIKE, bases: ['default', 'topo', 'cycle', 'satellite'] };
|
|
const RUN: TourMapLayerSet = { bases: ['default', 'topo', 'satellite'], defaultBase: 'default', overlays: [] };
|
|
const PADDLE: TourMapLayerSet = { bases: ['default', 'satellite'], defaultBase: 'default', overlays: ['seamarks'] };
|
|
const OTHER: TourMapLayerSet = { bases: ['default', 'satellite'], defaultBase: 'default', overlays: [] };
|
|
|
|
/** `hikingMap`, `cycleMap`: the admin allows OpenHikingMap (MAP-01) and CyclOSM (BIK-06) on this install. */
|
|
export function tourMapLayersFor(
|
|
type: TourTypeKey | null | undefined,
|
|
{ hikingMap = false, cycleMap = false }: { hikingMap?: boolean; cycleMap?: boolean } = {}
|
|
): TourMapLayerSet {
|
|
if (type === 'hike') return hikingMap ? HIKE_WITH_HIKING_MAP : HIKE;
|
|
if (type === 'bike') return cycleMap ? BIKE_WITH_CYCLE_MAP : BIKE;
|
|
if (type === 'run') return RUN;
|
|
if (type === 'kayak') return PADDLE;
|
|
return OTHER;
|
|
}
|
|
|
|
/** The base layer to show: the one chosen while this type offers it, else the type's own default. */
|
|
export function baseLayerFor(set: TourMapLayerSet, chosen: TourBaseLayer): TourBaseLayer {
|
|
return set.bases.includes(chosen) ? chosen : set.defaultBase;
|
|
}
|
|
|
|
/**
|
|
* OpenSeaMap's transparent seamark layer, as its embedding guide names it:
|
|
* HTTPS, the seamark path only, no basemap of theirs. Tiles CC-BY-SA 2.0, data
|
|
* ODbL. Checked on 16.10.2026: from zoom 6 to 18 every tile answers 200 with a
|
|
* PNG (an empty one is transparent), CORS open, no Cache-Control; so a failed
|
|
* tile means the service is unreachable, not that the water has no seamarks.
|
|
*/
|
|
export const SEAMARK_OVERLAY = {
|
|
id: 'seamarks',
|
|
url: 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png',
|
|
attribution:
|
|
'Seamarks © <a href="https://www.openseamap.org">OpenSeaMap</a> contributors (<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a>)',
|
|
minZoom: 6,
|
|
maxZoom: 18,
|
|
} as const;
|